summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r--src/mongo/db/ops/update.cpp277
-rw-r--r--src/mongo/db/ops/update.h104
-rw-r--r--src/mongo/db/ops/update_request.h167
-rw-r--r--src/mongo/db/ops/update_result.h57
4 files changed, 320 insertions, 285 deletions
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index 77f0b863019..5f0348412dc 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -36,122 +36,92 @@
#include "mongo/db/queryutil.h"
#include "mongo/db/storage/record.h"
#include "mongo/db/repl/oplog.h"
-#include "mongo/db/server_parameters.h"
#include "mongo/platform/unordered_set.h"
-//#define DEBUGUPDATE(x) cout << x << endl;
-#define DEBUGUPDATE(x)
-
namespace mongo {
- void checkNoMods( BSONObj o ) {
- BSONObjIterator i( o );
- while( i.moreWithEOO() ) {
- BSONElement e = i.next();
- if ( e.eoo() )
- break;
- uassert( 10154 , "Modifiers and non-modifiers cannot be mixed", e.fieldName()[ 0 ] != '$' );
+ namespace {
+
+ // TODO: Make this a function on NamespaceString, or make it cleaner.
+ inline void validateUpdate( const char* ns , const BSONObj& updateobj, const BSONObj& patternOrig ) {
+ uassert( 10155 , "cannot update reserved $ collection", strchr(ns, '$') == 0 );
+ if ( strstr(ns, ".system.") ) {
+ /* dm: it's very important that system.indexes is never updated as IndexDetails
+ has pointers into it */
+ uassert( 10156,
+ str::stream() << "cannot update system collection: "
+ << ns << " q: " << patternOrig << " u: " << updateobj,
+ legalClientSystemNS( ns , true ) );
+ }
}
- }
- static void checkTooLarge(const BSONObj& newObj) {
- uassert( 12522 , "$ operator made object too large" , newObj.objsize() <= BSONObjMaxUserSize );
- }
-
- /**
- * return a BSONObj with the _id field of the doc passed in. If no _id and multi, error.
- */
- BSONObj makeOplogEntryQuery(const BSONObj doc, bool multi) {
- BSONObjBuilder idPattern;
- BSONElement id;
- // NOTE: If the matching object lacks an id, we'll log
- // with the original pattern. This isn't replay-safe.
- // It might make sense to suppress the log instead
- // if there's no id.
- if ( doc.getObjectID( id ) ) {
- idPattern.append( id );
- return idPattern.obj();
- }
- else {
- uassert( 10157, "multi-update requires all modified objects to have an _id" , ! multi );
- return doc;
+ /**
+ * return a BSONObj with the _id field of the doc passed in. If no _id and multi, error.
+ */
+ BSONObj makeOplogEntryQuery(const BSONObj doc, bool multi) {
+ BSONObjBuilder idPattern;
+ BSONElement id;
+ // NOTE: If the matching object lacks an id, we'll log
+ // with the original pattern. This isn't replay-safe.
+ // It might make sense to suppress the log instead
+ // if there's no id.
+ if ( doc.getObjectID( id ) ) {
+ idPattern.append( id );
+ return idPattern.obj();
+ }
+ else {
+ uassert( 10157, "multi-update requires all modified objects to have an _id" , ! multi );
+ return doc;
+ }
}
- }
- void validateUpdate( const char* ns , const BSONObj& updateobj, const BSONObj& patternOrig ) {
- uassert( 10155 , "cannot update reserved $ collection", strchr(ns, '$') == 0 );
- if ( strstr(ns, ".system.") ) {
- /* dm: it's very important that system.indexes is never updated as IndexDetails
- has pointers into it */
- uassert( 10156,
- str::stream() << "cannot update system collection: "
- << ns << " q: " << patternOrig << " u: " << updateobj,
- legalClientSystemNS( ns , true ) );
- }
- }
+ } // namespace
- UpdateResult _updateObjects( bool su,
- const char* ns,
- const BSONObj& updateobj,
- const BSONObj& patternOrig,
- bool upsert,
- bool multi,
- bool logop ,
- OpDebug& debug,
- RemoveSaver* rs,
- bool fromMigrate,
- const QueryPlanSelectionPolicy& planPolicy,
- bool forReplication ) {
-
- // TODO: Put this logic someplace central and check based on constants (maybe using the
- // list of actually excluded config collections, and not global for the config db).
- NamespaceString nsStr( ns );
+ UpdateResult update(UpdateRequest& request) {
// Should the modifiers validate their embedded docs via okForStorage
// Only user updates should be checked. Any system or replication stuff should pass through.
// Config db docs shouldn't get checked for valid field names since the shard key can have
// a dot (".") in it.
- bool shouldValidate = !(forReplication || nsStr.isConfigDB());
+ bool shouldValidate = !(request.isFromReplication() ||
+ request.getNamespaceString().isConfigDB());
+ // TODO: Consider some sort of unification between the UpdateDriver, ModifierInterface
+ // and UpdateRequest structures.
UpdateDriver::Options opts;
- opts.multi = multi;
- opts.upsert = upsert;
- opts.logOp = logop;
- opts.modOptions = ModifierInterface::Options( forReplication, shouldValidate );
+ opts.multi = request.isMulti();
+ opts.upsert = request.isUpsert();
+ opts.logOp = request.shouldUpdateOpLog();
+ opts.modOptions = ModifierInterface::Options( request.isFromReplication(), shouldValidate );
UpdateDriver driver( opts );
- Status status = driver.parse( updateobj );
+ Status status = driver.parse( request.getUpdates() );
if ( !status.isOK() ) {
uasserted( 16840, status.reason() );
}
- return _updateObjects( &driver, su, ns, updateobj, patternOrig,
- upsert, multi, logop, debug, rs, fromMigrate,
- planPolicy, forReplication);
+ return update(request, &driver);
}
- UpdateResult _updateObjects( UpdateDriver* driver,
- bool su,
- const char* ns,
- const BSONObj& updateobj,
- const BSONObj& patternOrig,
- bool upsert,
- bool multi,
- bool logop ,
- OpDebug& debug,
- RemoveSaver* rs,
- bool fromMigrate,
- const QueryPlanSelectionPolicy& planPolicy,
- bool forReplication ) {
+ UpdateResult update(UpdateRequest& request, UpdateDriver* driver) {
- NamespaceDetails* d = nsdetails( ns );
- NamespaceDetailsTransient* nsdt = &NamespaceDetailsTransient::get( ns );
+ const NamespaceString& nsString = request.getNamespaceString();
- debug.updateobj = updateobj;
+ validateUpdate( nsString.ns().c_str(), request.getUpdates(), request.getQuery() );
- driver->refreshIndexKeys( nsdt->indexKeys() );
+ NamespaceDetails* nsDetails = nsdetails( nsString.ns() );
+ NamespaceDetailsTransient* nsDetailsTransient =
+ &NamespaceDetailsTransient::get( nsString.ns().c_str() );
- shared_ptr<Cursor> cursor = getOptimizedCursor( ns, patternOrig, BSONObj(), planPolicy );
+ OpDebug& debug = request.getDebug();
+
+ // TODO: This seems a bit circuitious.
+ debug.updateobj = request.getUpdates();
+
+ driver->refreshIndexKeys( nsDetailsTransient->indexKeys() );
+
+ shared_ptr<Cursor> cursor = getOptimizedCursor(
+ nsString.ns(), request.getQuery(), BSONObj(), request.getQueryPlanSelectionPolicy() );
// If the update was marked with '$isolated' (a.k.a '$atomic'), we are not allowed to
// yield while evaluating the update loop below.
@@ -215,7 +185,7 @@ namespace mongo {
// now if we have not yet done so.
if ( !clientCursor.get() )
clientCursor.reset(
- new ClientCursor( QueryOption_NoCursorTimeout, cursor, ns ) );
+ new ClientCursor( QueryOption_NoCursorTimeout, cursor, nsString.ns() ) );
// Ask the client cursor to yield. We get two bits of state back: whether or not
// we yielded, and whether or not we correctly recovered from yielding.
@@ -240,19 +210,19 @@ namespace mongo {
// our namespace may have changed while we were yielded, so we re-acquire
// them here. If we can't do so, escape the update loop. Otherwise, refresh
// the driver so that it knows about what is currently indexed.
- d = nsdetails( ns );
- if ( !d )
+ nsDetails = nsdetails( nsString.ns() );
+ if ( !nsDetails )
break;
- nsdt = &NamespaceDetailsTransient::get( ns );
+ nsDetailsTransient = &NamespaceDetailsTransient::get( nsString.ns().c_str() );
// TODO: This copies the index keys, but it may not need to do so.
- driver->refreshIndexKeys( nsdt->indexKeys() );
+ driver->refreshIndexKeys( nsDetailsTransient->indexKeys() );
}
}
// Let's fetch the next candidate object for this update.
- Record* r = cursor->_current();
+ Record* record = cursor->_current();
DiskLoc loc = cursor->currLoc();
const BSONObj oldObj = loc.obj();
@@ -280,7 +250,7 @@ namespace mongo {
cursor->advance();
continue;
}
- else if (!driver->isDocReplacement() && multi) {
+ else if (!driver->isDocReplacement() && request.isMulti()) {
// c)
cursor->advance();
if ( dedupHere ) {
@@ -313,7 +283,7 @@ namespace mongo {
// we also tell the cursor we're about to write a document that we've just seen.
// prepareToTouchEarlierIterate() requires calling later
// recoverFromTouchingEarlierIterate(), so we make a note here to do so.
- bool touchPreviousDoc = multi && cursor->ok();
+ bool touchPreviousDoc = request.isMulti() && cursor->ok();
if ( touchPreviousDoc ) {
if ( clientCursor.get() )
clientCursor->setDoingDeletes( true );
@@ -353,7 +323,7 @@ namespace mongo {
mutablebson::DamageVector damages;
bool inPlace = doc.getInPlaceUpdates(&damages, &source);
if ( inPlace && !damages.empty() && !driver->modsAffectIndices() ) {
- d->paddingFits();
+ nsDetails->paddingFits();
// All updates were in place. Apply them via durability and writing pointer.
mutablebson::DamageVector::const_iterator where = damages.begin();
@@ -374,10 +344,10 @@ namespace mongo {
// The updates were not in place. Apply them through the file manager.
newObj = doc.getObject();
- DiskLoc newLoc = theDataFileMgr.updateRecord(ns,
- d,
- nsdt,
- r,
+ DiskLoc newLoc = theDataFileMgr.updateRecord(nsString.ns().c_str(),
+ nsDetails,
+ nsDetailsTransient,
+ record,
loc,
newObj.objdata(),
newObj.objsize(),
@@ -397,10 +367,11 @@ namespace mongo {
}
// Log Obj
- if ( logop ) {
+ if ( request.shouldUpdateOpLog() ) {
if ( driver->isDocReplacement() || !logObj.isEmpty() ) {
- BSONObj idQuery = driver->makeOplogEntryQuery(newObj, multi);
- logOp("u", ns, logObj , &idQuery, 0, fromMigrate, &newObj);
+ BSONObj idQuery = driver->makeOplogEntryQuery(newObj, request.isMulti());
+ logOp("u", nsString.ns().c_str(), logObj , &idQuery,
+ NULL, request.isFromMigration(), &newObj);
}
}
@@ -408,7 +379,7 @@ namespace mongo {
if (!objectWasChanged)
debug.nupdateNoops++;
- if (!multi) {
+ if (!request.isMulti()) {
break;
}
@@ -422,18 +393,14 @@ namespace mongo {
}
- if (numMatched > 0) {
- return UpdateResult( true /* updated existing object(s) */,
+ // TODO: Can this be simplified?
+ if ((numMatched > 0) || (numMatched == 0 && !request.isUpsert()) ) {
+ debug.nupdated = numMatched;
+ return UpdateResult( numMatched > 0 /* updated existing object(s) */,
!driver->isDocReplacement() /* $mod or obj replacement */,
numMatched /* # of docments update, even no-ops */,
BSONObj() );
}
- else if (numMatched == 0 && !upsert) {
- return UpdateResult( false /* no object updated */,
- !driver->isDocReplacement() /* $mod or obj replacement */,
- 0 /* no updates */,
- BSONObj() );
- }
//
// We haven't found any existing document so an insert is done
@@ -452,8 +419,8 @@ namespace mongo {
// Reset the document we will be writing to
doc.reset( baseObj, mutablebson::Document::kInPlaceDisabled );
- if ( patternOrig.hasElement("_id") ) {
- uassertStatusOK(doc.root().appendElement(patternOrig.getField("_id")));
+ if ( request.getQuery().hasElement("_id") ) {
+ uassertStatusOK(doc.root().appendElement(request.getQuery().getField("_id")));
}
@@ -461,8 +428,8 @@ namespace mongo {
// query and the mods. Otherwise, we can use the object replacement sent by the user
// update command that was parsed by the driver before.
// In the following block we handle the query part, and then do the regular mods after.
- if ( *updateobj.firstElementFieldName() == '$' ) {
- uassertStatusOK(UpdateDriver::createFromQuery(patternOrig, doc));
+ if ( *request.getUpdates().firstElementFieldName() == '$' ) {
+ uassertStatusOK(UpdateDriver::createFromQuery(request.getQuery(), doc));
debug.fastmodinsert = true;
}
@@ -473,85 +440,19 @@ namespace mongo {
}
BSONObj newObj = doc.getObject();
- theDataFileMgr.insertWithObjMod( ns, newObj, false, su );
- if ( logop ) {
- logOp( "i", ns, newObj, 0, 0, fromMigrate, &newObj );
+ theDataFileMgr.insertWithObjMod( nsString.ns().c_str(), newObj, false, request.isGod() );
+ if ( request.shouldUpdateOpLog() ) {
+ logOp( "i", nsString.ns().c_str(), newObj,
+ NULL, NULL, request.isFromMigration(), &newObj );
}
+ debug.nupdated = 1;
return UpdateResult( false /* updated a non existing document */,
!driver->isDocReplacement() /* $mod or obj replacement? */,
1 /* count of updated documents */,
newObj /* object that was upserted */ );
}
- UpdateResult updateObjects( const char* ns,
- const BSONObj& updateobj,
- const BSONObj& patternOrig,
- bool upsert,
- bool multi,
- bool logop ,
- OpDebug& debug,
- bool fromMigrate,
- const QueryPlanSelectionPolicy& planPolicy ) {
-
- validateUpdate( ns , updateobj , patternOrig );
-
- UpdateResult ur = _updateObjects(false, ns, updateobj, patternOrig,
- upsert, multi, logop,
- debug, NULL, fromMigrate, planPolicy );
- debug.nupdated = ur.num;
- return ur;
- }
-
- UpdateResult updateObjects( UpdateDriver* driver,
- const char* ns,
- const BSONObj& updateobj,
- const BSONObj& patternOrig,
- bool upsert,
- bool multi,
- bool logop ,
- OpDebug& debug,
- bool fromMigrate,
- const QueryPlanSelectionPolicy& planPolicy ) {
-
- validateUpdate( ns , updateobj , patternOrig );
-
- UpdateResult ur = _updateObjects(driver, false, ns, updateobj, patternOrig,
- upsert, multi, logop,
- debug, NULL, fromMigrate, planPolicy );
- debug.nupdated = ur.num;
- return ur;
- }
-
- UpdateResult updateObjectsForReplication( const char* ns,
- const BSONObj& updateobj,
- const BSONObj& patternOrig,
- bool upsert,
- bool multi,
- bool logop ,
- OpDebug& debug,
- bool fromMigrate,
- const QueryPlanSelectionPolicy& planPolicy ) {
-
- validateUpdate( ns , updateobj , patternOrig );
-
- UpdateResult ur = _updateObjects(false,
- ns,
- updateobj,
- patternOrig,
- upsert,
- multi,
- logop,
- debug,
- NULL /* no remove saver */,
- fromMigrate,
- planPolicy,
- true /* for replication */ );
- debug.nupdated = ur.num;
- return ur;
-
- }
-
BSONObj applyUpdateOperators( const BSONObj& from, const BSONObj& operators ) {
UpdateDriver::Options opts;
opts.multi = false;
diff --git a/src/mongo/db/ops/update.h b/src/mongo/db/ops/update.h
index f4088c90bc4..8f42e30ac16 100644
--- a/src/mongo/db/ops/update.h
+++ b/src/mongo/db/ops/update.h
@@ -16,118 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "mongo/pch.h"
+#pragma once
#include "mongo/db/jsobj.h"
#include "mongo/db/curop.h"
+#include "mongo/db/ops/update_request.h"
+#include "mongo/db/ops/update_result.h"
#include "mongo/db/query_plan_selection_policy.h"
namespace mongo {
class UpdateDriver;
- // ---------- public -------------
-
- struct UpdateResult {
- const bool existing; // if existing objects were modified
- const bool mod; // was this a $ mod
- const long long num; // how many objects touched
- OID upserted; // if something was upserted, the new _id of the object
-
- UpdateResult( bool e, bool m, unsigned long long n , const BSONObj& upsertedObject )
- : existing(e) , mod(m), num(n) {
- upserted.clear();
- BSONElement id = upsertedObject["_id"];
- if ( ! e && n == 1 && id.type() == jstOID ) {
- upserted = id.OID();
- }
- }
- };
-
- class RemoveSaver;
-
- /* returns true if an existing object was updated, false if no existing object was found.
- multi - update multiple objects - mostly useful with things like $set
- su - allow access to system namespaces (super user)
- */
- UpdateResult updateObjects(const char* ns,
- const BSONObj& updateobj,
- const BSONObj& pattern,
- bool upsert,
- bool multi,
- bool logop,
- OpDebug& debug,
- bool fromMigrate = false,
- const QueryPlanSelectionPolicy& planPolicy = QueryPlanSelectionPolicy::any());
-
- /** A variant of updateObjects that is only useable if the new update framework is enabled.
- * It assumes that the UpdateDriver has already been initialized outside the lock.
- */
- UpdateResult updateObjects(UpdateDriver* driver,
- const char* ns,
- const BSONObj& updateobj,
- const BSONObj& pattern,
- bool upsert,
- bool multi,
- bool logop,
- OpDebug& debug,
- bool fromMigrate = false,
- const QueryPlanSelectionPolicy& planPolicy = QueryPlanSelectionPolicy::any());
-
- /*
- * Similar to updateObjects but not strict about applying mods that can fail during initial
- * replication.
- *
- * Reference ticket: SERVER-4781
- */
- UpdateResult updateObjectsForReplication(const char* ns,
- const BSONObj& updateobj,
- const BSONObj& pattern,
- bool upsert,
- bool multi,
- bool logop,
- OpDebug& debug,
- bool fromMigrate = false,
- const QueryPlanSelectionPolicy& planPolicy =
- QueryPlanSelectionPolicy::any());
-
- UpdateResult _updateObjects(bool su,
- const char* ns,
- const BSONObj& updateobj,
- const BSONObj& pattern,
- bool upsert,
- bool multi,
- bool logop,
- OpDebug& debug,
- RemoveSaver* rs = 0,
- bool fromMigrate = false,
- const QueryPlanSelectionPolicy& planPolicy
- = QueryPlanSelectionPolicy::any(),
- bool forReplication = false);
-
- UpdateResult _updateObjects(UpdateDriver* driver,
- bool su,
- const char* ns,
- const BSONObj& updateobj,
- const BSONObj& pattern,
- bool upsert,
- bool multi,
- bool logop,
- OpDebug& debug,
- RemoveSaver* rs = 0,
- bool fromMigrate = false,
- const QueryPlanSelectionPolicy& planPolicy
- = QueryPlanSelectionPolicy::any(),
- bool forReplication = false);
+ UpdateResult update(UpdateRequest& request);
+ UpdateResult update(UpdateRequest& request, UpdateDriver* driver);
/**
* takes the from document and returns a new document
- * after apply all the operators
- * e.g.
+ * after apply all the operators
+ * e.g.
* applyUpdateOperators( BSON( "x" << 1 ) , BSON( "$inc" << BSON( "x" << 1 ) ) );
* returns: { x : 2 }
*/
BSONObj applyUpdateOperators( const BSONObj& from, const BSONObj& operators );
-
} // namespace mongo
diff --git a/src/mongo/db/ops/update_request.h b/src/mongo/db/ops/update_request.h
new file mode 100644
index 00000000000..5384a8b5dcd
--- /dev/null
+++ b/src/mongo/db/ops/update_request.h
@@ -0,0 +1,167 @@
+/**
+ * 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/db/jsobj.h"
+#include "mongo/db/curop.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/query_plan_selection_policy.h"
+
+namespace mongo {
+
+ class UpdateRequest {
+ public:
+ inline UpdateRequest(
+ const NamespaceString& nsString,
+ OpDebug& debug,
+ const QueryPlanSelectionPolicy& policy = QueryPlanSelectionPolicy::any() )
+ : _nsString(nsString)
+ , _debug(debug)
+ , _queryPlanPolicy(policy)
+ , _god(false)
+ , _upsert(false)
+ , _multi(false)
+ , _updateOpLog(false)
+ , _fromMigration(false)
+ , _fromReplication(false) {}
+
+ const NamespaceString& getNamespaceString() const {
+ return _nsString;
+ }
+
+ OpDebug& getDebug() {
+ return _debug;
+ }
+
+ const OpDebug& getDebug() const {
+ return _debug;
+ }
+
+ const QueryPlanSelectionPolicy& getQueryPlanSelectionPolicy() const {
+ return _queryPlanPolicy;
+ }
+
+ inline UpdateRequest& query(const BSONObj& query) {
+ _query = query;
+ return *this;
+ }
+
+ inline const BSONObj& getQuery() const {
+ return _query;
+ }
+
+ inline UpdateRequest& updates(const BSONObj& updates) {
+ _updates = updates;
+ return *this;
+ }
+
+ inline const BSONObj& getUpdates() const {
+ return _updates;
+ }
+
+ // Please see documentation on the private members matching these names for
+ // explanations of the following fields.
+
+ inline UpdateRequest& god(bool value = true) {
+ _god = value;
+ return *this;
+ }
+
+ bool isGod() const {
+ return _god;
+ }
+
+ inline UpdateRequest& upsert(bool value = true) {
+ _upsert = value;
+ return *this;
+ }
+
+ bool isUpsert() const {
+ return _upsert;
+ }
+
+ inline UpdateRequest& multi(bool value = true) {
+ _multi = value;
+ return *this;
+ }
+
+ bool isMulti() const {
+ return _multi;
+ }
+
+ inline UpdateRequest& updateOpLog(bool value = true) {
+ _updateOpLog = value;
+ return *this;
+ }
+
+ bool shouldUpdateOpLog() const {
+ return _updateOpLog;
+ }
+
+ inline UpdateRequest& fromMigration(bool value = true) {
+ _fromMigration = value;
+ return *this;
+ }
+
+ bool isFromMigration() const {
+ return _fromMigration;
+ }
+
+ inline UpdateRequest& fromReplication(bool value = true) {
+ _fromReplication = value;
+ return *this;
+ }
+
+ bool isFromReplication() const {
+ return _fromReplication;
+ }
+
+ private:
+
+ const NamespaceString& _nsString;
+ OpDebug& _debug;
+ const QueryPlanSelectionPolicy& _queryPlanPolicy;
+
+ // Contains the query that selects documents to update.
+ BSONObj _query;
+
+ // Contains the modifiers to apply to matched objects, or a replacement document.
+ BSONObj _updates;
+
+ // Flags controlling the update.
+
+ // God bypasses _id checking and index generation. It is only used on behalf of system
+ // updates, never user updates.
+ bool _god;
+
+ // True if this should insert if no matching document is found.
+ bool _upsert;
+
+ // True if this update is allowed to affect more than one document.
+ bool _multi;
+
+ // True if the effects of the update should be written to the oplog.
+ bool _updateOpLog;
+
+ // True if this update is on behalf of a chunk migration.
+ bool _fromMigration;
+
+ // True if this update is being applied during the application for the oplog.
+ bool _fromReplication;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/ops/update_result.h b/src/mongo/db/ops/update_result.h
new file mode 100644
index 00000000000..00578daaa6d
--- /dev/null
+++ b/src/mongo/db/ops/update_result.h
@@ -0,0 +1,57 @@
+/**
+ * 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/db/jsobj.h"
+#include "mongo/db/curop.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/query_plan_selection_policy.h"
+
+namespace mongo {
+
+ struct UpdateResult {
+
+ UpdateResult( bool existing_,
+ bool modifiers_,
+ unsigned long long numMatched_,
+ const BSONObj& upsertedObject_ )
+ : existing(existing_)
+ , modifiers(modifiers_)
+ , numMatched(numMatched_) {
+
+ upserted.clear();
+ BSONElement id = upsertedObject_["_id"];
+ if ( ! existing && numMatched == 1 && id.type() == jstOID ) {
+ upserted = id.OID();
+ }
+ }
+
+
+ // if existing objects were modified
+ const bool existing;
+
+ // was this a $ mod
+ const bool modifiers;
+
+ // how many objects touched
+ const long long numMatched;
+
+ // if something was upserted, the new _id of the object
+ OID upserted;
+ };
+
+} // namespace mongo