summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/ops/update_internal.cpp42
-rw-r--r--src/mongo/db/ops/update_internal.h4
-rw-r--r--src/mongo/dbtests/repltests.cpp18
-rw-r--r--src/mongo/dbtests/updatetests.cpp4
4 files changed, 58 insertions, 10 deletions
diff --git a/src/mongo/db/ops/update_internal.cpp b/src/mongo/db/ops/update_internal.cpp
index dccc22e0175..5486b0a3466 100644
--- a/src/mongo/db/ops/update_internal.cpp
+++ b/src/mongo/db/ops/update_internal.cpp
@@ -21,6 +21,7 @@
#include "mongo/db/oplog.h"
#include "mongo/db/jsobjmanipulator.h"
#include "mongo/db/pdfile.h"
+#include "mongo/util/mongoutils/str.h"
#include "update_internal.h"
@@ -124,9 +125,21 @@ namespace mongo {
}
bb.append( elt );
- ms.fixedOpName = "$set";
- ms.forceEmptyArray = true;
- ms.fixedArray = BSONArray(bb.done().getOwned());
+
+ // We don't want to log a $set for which the '_checkForAppending' test won't pass. If we're
+ // in that case, fall back to non-optimized logging.
+ if ( (elt.type() == Object && elt.embeddedObject().okForStorage()) || (elt.type() != Object) ) {
+ ms.fixedOpName = "$set";
+ ms.forcePositional = true;
+ ms.position = bb.arrSize() - 1;
+ bb.done();
+ }
+ else {
+ ms.fixedOpName = "$set";
+ ms.forceEmptyArray = true;
+ ms.fixedArray = BSONArray( bb.done().getOwned() );
+ }
+
break;
}
@@ -157,6 +170,9 @@ namespace mongo {
}
}
+ ms.fixedOpName = "$set";
+ ms.forceEmptyArray = true;
+ ms.fixedArray = BSONArray(bb.done().getOwned());
}
else {
@@ -169,14 +185,20 @@ namespace mongo {
found = true;
}
- if ( ! found )
+ if ( ! found ) {
bb.append( elt );
-
+ ms.fixedOpName = "$set";
+ ms.forcePositional = true;
+ ms.position = bb.arrSize() - 1;
+ bb.done();
+
+ } else {
+ ms.fixedOpName = "$set";
+ ms.forceEmptyArray = true;
+ ms.fixedArray = BSONArray(bb.done().getOwned());
+ }
}
- ms.fixedOpName = "$set";
- ms.forceEmptyArray = true;
- ms.fixedArray = BSONArray(bb.done().getOwned());
break;
}
@@ -568,6 +590,10 @@ namespace mongo {
else if ( ! fixedArray.isEmpty() || forceEmptyArray ) {
bb.append( m->fieldName, fixedArray );
}
+ else if ( forcePositional ) {
+ string positionalField = str::stream() << m->fieldName << "." << position;
+ bb.appendAs( m->elt, positionalField.c_str() );
+ }
else {
bb.appendAs( m->elt , m->fieldName );
}
diff --git a/src/mongo/db/ops/update_internal.h b/src/mongo/db/ops/update_internal.h
index e3aa8c8dcf9..1b8f27bb700 100644
--- a/src/mongo/db/ops/update_internal.h
+++ b/src/mongo/db/ops/update_internal.h
@@ -401,6 +401,8 @@ namespace mongo {
BSONElement* fixed;
BSONArray fixedArray;
bool forceEmptyArray;
+ bool forcePositional;
+ int position;
int DEPRECATED_pushStartSize;
BSONType incType;
@@ -414,6 +416,8 @@ namespace mongo {
fixedOpName = 0;
fixed = 0;
forceEmptyArray = false;
+ forcePositional = false;
+ position = 0;
DEPRECATED_pushStartSize = -1;
incType = EOO;
dontApply = false;
diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp
index 836670240a6..d3b131a5a41 100644
--- a/src/mongo/dbtests/repltests.cpp
+++ b/src/mongo/dbtests/repltests.cpp
@@ -815,6 +815,23 @@ namespace ReplTests {
}
};
+ class PushWithDollarSigns : public Base {
+ void doIt() const {
+ client()->update( ns(),
+ BSON( "_id" << 0),
+ BSON( "$push" << BSON( "a" << BSON( "$foo" << 1 ) ) ) );
+ }
+ using ReplTests::Base::check;
+ void check() const {
+ ASSERT_EQUALS( 1, count() );
+ check( fromjson( "{'_id':0, a:[0, {'$foo':1}]}"), one( fromjson( "{'_id':0}" ) ) );
+ }
+ void reset() const {
+ deleteAll( ns() );
+ insert( BSON( "_id" << 0 << "a" << BSON_ARRAY( 0 ) ) );
+ }
+ };
+
class PushAllUpsert : public Base {
public:
void doIt() const {
@@ -1288,6 +1305,7 @@ namespace ReplTests {
add< Idempotence::EmptyPush >();
add< Idempotence::EmptyPushSparseIndex >();
add< Idempotence::PushAll >();
+ add< Idempotence::PushWithDollarSigns >();
add< Idempotence::PushAllUpsert >();
add< Idempotence::EmptyPushAll >();
add< Idempotence::Pull >();
diff --git a/src/mongo/dbtests/updatetests.cpp b/src/mongo/dbtests/updatetests.cpp
index 28efdfe5787..a014eefe9f9 100644
--- a/src/mongo/dbtests/updatetests.cpp
+++ b/src/mongo/dbtests/updatetests.cpp
@@ -722,7 +722,7 @@ namespace UpdateTests {
auto_ptr<ModSetState> modSetState = modSet.prepare( obj );
ASSERT_FALSE( modSetState->canApplyInPlace() );
modSetState->createNewFromMods();
- ASSERT_EQUALS( BSON( "$set" << BSON( "a" << BSON_ARRAY( 1 << 2 << 3 ) ) ),
+ ASSERT_EQUALS( BSON( "$set" << BSON( "a.2" << 3 ) ),
modSetState->getOpLogRewrite() );
}
};
@@ -949,7 +949,7 @@ namespace UpdateTests {
auto_ptr<ModSetState> modSetState = modSet.prepare( obj );
ASSERT_FALSE( modSetState->canApplyInPlace() );
modSetState->createNewFromMods();
- ASSERT_EQUALS( BSON( "$set" << BSON( "a" << BSON_ARRAY( 1 << 2 ) ) ),
+ ASSERT_EQUALS( BSON( "$set" << BSON( "a.1" << 2 ) ),
modSetState->getOpLogRewrite() );
}
};