summaryrefslogtreecommitdiff
path: root/src/mongo/db/update
diff options
context:
space:
mode:
authorIan Boros <ian.boros@mongodb.com>2020-09-03 14:14:48 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-09-16 18:31:07 +0000
commit01ed0776388cc8cff83a82e3671d313b00d5096d (patch)
tree523737fcd604917af6cd48a685c0746c3405c100 /src/mongo/db/update
parentcc248c4286d45eee06e2d66cdd52cd7cbae5b593 (diff)
downloadmongo-01ed0776388cc8cff83a82e3671d313b00d5096d.tar.gz
SERVER-50300 Change modifier style updates to use the $v:2 oplog format
Diffstat (limited to 'src/mongo/db/update')
-rw-r--r--src/mongo/db/update/addtoset_node_test.cpp64
-rw-r--r--src/mongo/db/update/arithmetic_node_test.cpp81
-rw-r--r--src/mongo/db/update/bit_node_test.cpp32
-rw-r--r--src/mongo/db/update/compare_node_test.cpp55
-rw-r--r--src/mongo/db/update/current_date_node_test.cpp64
-rw-r--r--src/mongo/db/update/delta_executor.cpp4
-rw-r--r--src/mongo/db/update/delta_executor.h10
-rw-r--r--src/mongo/db/update/pop_node_test.cpp38
-rw-r--r--src/mongo/db/update/pull_node_test.cpp86
-rw-r--r--src/mongo/db/update/pullall_node_test.cpp30
-rw-r--r--src/mongo/db/update/push_node_test.cpp105
-rw-r--r--src/mongo/db/update/rename_node_test.cpp58
-rw-r--r--src/mongo/db/update/set_node_test.cpp98
-rw-r--r--src/mongo/db/update/unset_node.cpp9
-rw-r--r--src/mongo/db/update/unset_node_test.cpp56
-rw-r--r--src/mongo/db/update/update_array_node_test.cpp59
-rw-r--r--src/mongo/db/update/update_node_test_fixture.h54
-rw-r--r--src/mongo/db/update/update_object_node_test.cpp95
-rw-r--r--src/mongo/db/update/update_tree_executor.h13
-rw-r--r--src/mongo/db/update/v2_log_builder.cpp313
-rw-r--r--src/mongo/db/update/v2_log_builder.h6
21 files changed, 926 insertions, 404 deletions
diff --git a/src/mongo/db/update/addtoset_node_test.cpp b/src/mongo/db/update/addtoset_node_test.cpp
index c9b691126ee..d2b7f90be65 100644
--- a/src/mongo/db/update/addtoset_node_test.cpp
+++ b/src/mongo/db/update/addtoset_node_test.cpp
@@ -135,7 +135,9 @@ TEST_F(AddToSetNodeTest, ApplyNonEach) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1]}}"), fromjson("{$v: 2, diff: {u: {a: [0, 1]}}}"));
+
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -153,7 +155,9 @@ TEST_F(AddToSetNodeTest, ApplyNonEachArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, [1]]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, [1]]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, [1]]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [0, [1]]}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -171,7 +175,9 @@ TEST_F(AddToSetNodeTest, ApplyEach) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1, 2]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [0, 1, 2]}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -189,7 +195,8 @@ TEST_F(AddToSetNodeTest, ApplyToEmptyArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 2]}}"), fromjson("{$v: 2, diff: {u: {a: [1, 2]}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -207,7 +214,9 @@ TEST_F(AddToSetNodeTest, ApplyDeduplicateElementsToAdd) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1]}}"), fromjson("{$v: 2, diff: {u: {a: [0, 1]}}}"));
+
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -225,7 +234,9 @@ TEST_F(AddToSetNodeTest, ApplyDoNotAddExistingElements) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1]}}"), fromjson("{$v: 2, diff: {u: {a: [0, 1]}}}"));
+
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -243,7 +254,9 @@ TEST_F(AddToSetNodeTest, ApplyDoNotDeduplicateExistingElements) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 0, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 0, 1]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [0, 0, 1]}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -261,7 +274,8 @@ TEST_F(AddToSetNodeTest, ApplyNoElementsToAdd) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -279,7 +293,8 @@ TEST_F(AddToSetNodeTest, ApplyNoNonDuplicateElementsToAdd) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -297,7 +312,8 @@ TEST_F(AddToSetNodeTest, ApplyCreateArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1]}}"), fromjson("{$v: 2, diff: {i: {a: [0, 1]}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -315,7 +331,8 @@ TEST_F(AddToSetNodeTest, ApplyCreateEmptyArrayIsNotNoop) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {i: {a: []}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -336,7 +353,9 @@ TEST_F(AddToSetNodeTest, ApplyDeduplicationOfElementsToAddRespectsCollation) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['abc', 'def']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['abc', 'def']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['abc', 'def']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['abc', 'def']}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -357,7 +376,9 @@ TEST_F(AddToSetNodeTest, ApplyComparisonToExistingElementsRespectsCollation) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['ABC', 'def']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['ABC', 'def']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['ABC', 'def']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['ABC', 'def']}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -379,7 +400,10 @@ TEST_F(AddToSetNodeTest, ApplyRespectsCollationFromSetCollator) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['abc', 'def']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['abc', 'def']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['abc', 'def']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['abc', 'def']}}}"));
+
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -414,15 +438,18 @@ TEST_F(AddToSetNodeTest, ApplyNestedArray) {
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a.1"], expCtx));
- mutablebson::Document doc(fromjson("{ _id : 1, a : [ 1, [ ] ] }"));
+ mutablebson::Document doc(fromjson("{ _id : 1, a : [1, []] }"));
setPathTaken(makeRuntimeUpdatePathForTest("a.1"));
addIndexedPath("a");
auto result = node.apply(getApplyParams(doc.root()["a"][1]), getUpdateNodeApplyParams());
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
- ASSERT_EQUALS(fromjson("{ _id : 1, a : [ 1, [ 1 ] ] }"), doc);
+ ASSERT_EQUALS(fromjson("{ _id : 1, a : [1, [1]] }"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ $set : { 'a.1' : [ 1 ] } }"), getLogDoc());
+
+ assertOplogEntry(fromjson("{ $set : { 'a.1' : [1] } }"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: [1]}}}"));
+
ASSERT_EQUALS(getModifiedPaths(), "{a.1}");
}
@@ -439,7 +466,8 @@ TEST_F(AddToSetNodeTest, ApplyIndexesNotAffected) {
ASSERT_FALSE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1]}}"), fromjson("{$v: 2, diff: {u: {a: [0, 1]}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
diff --git a/src/mongo/db/update/arithmetic_node_test.cpp b/src/mongo/db/update/arithmetic_node_test.cpp
index 03941282e4a..3cb73d8f8e7 100644
--- a/src/mongo/db/update/arithmetic_node_test.cpp
+++ b/src/mongo/db/update/arithmetic_node_test.cpp
@@ -127,7 +127,8 @@ TEST_F(ArithmeticNodeTest, ApplyIncNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -145,7 +146,8 @@ TEST_F(ArithmeticNodeTest, ApplyMulNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -163,7 +165,8 @@ TEST_F(ArithmeticNodeTest, ApplyRoundingNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 6.022e23}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -181,7 +184,8 @@ TEST_F(ArithmeticNodeTest, ApplyEmptyPathToCreate) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 11}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 11}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 11}}"), fromjson("{$v: 2, diff: {u: {a: 11}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -200,7 +204,9 @@ TEST_F(ArithmeticNodeTest, ApplyCreatePath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {d: 5, b: {c: 6}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b.c': 6}}"),
+ fromjson("{$v: 2, diff: {sa: {i: {b: {c: 6}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b.c}");
}
@@ -236,7 +242,8 @@ TEST_F(ArithmeticNodeTest, ApplyCreatePathFromRoot) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{c: 5, a: {b: 6}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 6}}"), fromjson("{$v: 2, diff: {i: {a: {b: 6}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -255,7 +262,9 @@ TEST_F(ArithmeticNodeTest, ApplyPositional) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 7, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 7}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': 7}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: 7}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.1}");
}
@@ -292,7 +301,8 @@ TEST_F(ArithmeticNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -378,7 +388,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionFromIntToDecimalIsNotANoOp) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"5.0\")}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.0\")}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: NumberDecimal('5.0')}}"),
+ fromjson("{$v: 2, diff: {u: {a: NumberDecimal('5.0')}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -396,7 +408,9 @@ TEST_F(ArithmeticNodeTest, TypePromotionFromLongToDecimalIsNotANoOp) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"5.0\")}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.0\")}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: NumberDecimal('5.0')}}"),
+ fromjson("{$v: 2, diff: {u: {a: NumberDecimal('5.0')}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -414,7 +428,13 @@ TEST_F(ArithmeticNodeTest, TypePromotionFromDoubleToDecimalIsNotANoOp) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"5.25\")}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.25\")}}"), getLogDoc());
+
+ assertOplogEntry(
+ fromjson("{$set: {a: NumberDecimal('5.25')}}"),
+ fromjson("{$v: 2, diff: {u: {a: NumberDecimal('5.25')}}}"),
+ false // Not checking binary equality because the NumberDecimal in the expected output may
+ // not be bitwise identical to the result produced by the update system.
+ );
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -449,7 +469,13 @@ TEST_F(ArithmeticNodeTest, IncrementedDecimalStaysDecimal) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"11.5\")}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"11.5\")}}"), getLogDoc());
+
+ assertOplogEntry(
+ fromjson("{$set: {a: NumberDecimal('11.5')}}"),
+ fromjson("{$v: 2, diff: {u: {a: NumberDecimal('11.5')}}}"),
+ false // Not checking binary equality because the NumberDecimal in the expected output may
+ // not be bitwise identical to the result produced by the update system.
+ );
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -669,8 +695,8 @@ TEST_F(ArithmeticNodeTest, ApplyEmptyIndexData) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: 3}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: 3}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 3}}"), fromjson("{$v: 2, diff: {u: {a: 3}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -1002,8 +1028,9 @@ TEST_F(ArithmeticNodeTest, ApplyLogDottedPath) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: [{b:0}, {b:1}, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: {b: 2}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -1019,8 +1046,9 @@ TEST_F(ArithmeticNodeTest, LogEmptyArray) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: [null, null, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: {b: 2}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -1036,8 +1064,9 @@ TEST_F(ArithmeticNodeTest, LogEmptyObject) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {i: {'2': {b: 2}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.2.b}");
}
@@ -1057,7 +1086,8 @@ TEST_F(ArithmeticNodeTest, ApplyDeserializedDocNotNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1, b: NumberInt(0)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {b: NumberInt(0)}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: NumberInt(0)}}"), fromjson("{$v: 2, diff: {i: {b: 0}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{b}");
}
@@ -1077,7 +1107,8 @@ TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberInt(2)}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -1097,7 +1128,8 @@ TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNoop) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: NumberInt(1)}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -1117,7 +1149,8 @@ TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNotNoop) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 3}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 3}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 3}}"), fromjson("{$v: 2, diff: {sa: {u: {b: 3}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
diff --git a/src/mongo/db/update/bit_node_test.cpp b/src/mongo/db/update/bit_node_test.cpp
index b8e652b1acf..e3903c6a301 100644
--- a/src/mongo/db/update/bit_node_test.cpp
+++ b/src/mongo/db/update/bit_node_test.cpp
@@ -163,7 +163,8 @@ TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentAnd) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 0}}"), fromjson("{$v: 2, diff: {i: {a: 0}}}"));
}
TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentOr) {
@@ -178,7 +179,8 @@ TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentOr) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 1}}"), fromjson("{$v: 2, diff: {i: {a: 1}}}"));
}
TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentXor) {
@@ -193,7 +195,8 @@ TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentXor) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 1}}"), fromjson("{$v: 2, diff: {i: {a: 1}}}"));
}
TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentAnd) {
@@ -208,7 +211,9 @@ TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentAnd) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0100), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0100)), getLogDoc());
+
+ assertOplogEntry(BSON("$set" << BSON("a" << 0b0100)),
+ BSON("$v" << 2 << "diff" << BSON("u" << BSON("a" << 0b0100))));
}
TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentOr) {
@@ -223,7 +228,9 @@ TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentOr) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0111), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0111)), getLogDoc());
+
+ assertOplogEntry(BSON("$set" << BSON("a" << 0b0111)),
+ BSON("$v" << 2 << "diff" << BSON("u" << BSON("a" << 0b0111))));
}
TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentXor) {
@@ -238,7 +245,9 @@ TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentXor) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0011), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0011)), getLogDoc());
+
+ assertOplogEntry(BSON("$set" << BSON("a" << 0b0011)),
+ BSON("$v" << 2 << "diff" << BSON("u" << BSON("a" << 0b0011))));
}
TEST_F(BitNodeTest, ApplyShouldReportNoOp) {
@@ -253,7 +262,8 @@ TEST_F(BitNodeTest, ApplyShouldReportNoOp) {
ASSERT_TRUE(result.noop);
ASSERT_EQUALS(BSON("a" << static_cast<int>(1)), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(BitNodeTest, ApplyMultipleBitOps) {
@@ -273,7 +283,9 @@ TEST_F(BitNodeTest, ApplyMultipleBitOps) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0101011001100110), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0101011001100110)), getLogDoc());
+
+ assertOplogEntry(BSON("$set" << BSON("a" << 0b0101011001100110)),
+ BSON("$v" << 2 << "diff" << BSON("u" << BSON("a" << 0b0101011001100110))));
}
TEST_F(BitNodeTest, ApplyRepeatedBitOps) {
@@ -288,7 +300,9 @@ TEST_F(BitNodeTest, ApplyRepeatedBitOps) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b10010110), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b10010110)), getLogDoc());
+
+ assertOplogEntry(BSON("$set" << BSON("a" << 0b10010110)),
+ BSON("$v" << 2 << "diff" << BSON("u" << BSON("a" << 0b10010110))));
}
} // namespace
diff --git a/src/mongo/db/update/compare_node_test.cpp b/src/mongo/db/update/compare_node_test.cpp
index a04c84f852f..e3a608ea535 100644
--- a/src/mongo/db/update/compare_node_test.cpp
+++ b/src/mongo/db/update/compare_node_test.cpp
@@ -70,7 +70,8 @@ TEST_F(CompareNodeTest, ApplyMaxSameNumber) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMinSameNumber) {
@@ -87,7 +88,8 @@ TEST_F(CompareNodeTest, ApplyMinSameNumber) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMaxNumberIsLess) {
@@ -104,7 +106,8 @@ TEST_F(CompareNodeTest, ApplyMaxNumberIsLess) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMinNumberIsMore) {
@@ -121,7 +124,8 @@ TEST_F(CompareNodeTest, ApplyMinNumberIsMore) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMaxSameValInt) {
@@ -138,7 +142,8 @@ TEST_F(CompareNodeTest, ApplyMaxSameValInt) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1.0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMaxSameValIntZero) {
@@ -155,7 +160,8 @@ TEST_F(CompareNodeTest, ApplyMaxSameValIntZero) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0.0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMinSameValIntZero) {
@@ -172,7 +178,8 @@ TEST_F(CompareNodeTest, ApplyMinSameValIntZero) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0.0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMissingFieldMinNumber) {
@@ -189,7 +196,8 @@ TEST_F(CompareNodeTest, ApplyMissingFieldMinNumber) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 0}}"), fromjson("{$v:2, diff: {i: {a: 0}}}"));
}
TEST_F(CompareNodeTest, ApplyExistingNumberMinNumber) {
@@ -206,7 +214,8 @@ TEST_F(CompareNodeTest, ApplyExistingNumberMinNumber) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 0}}"), fromjson("{$v:2, diff: {u: {a: 0}}}"));
}
TEST_F(CompareNodeTest, ApplyMissingFieldMaxNumber) {
@@ -223,7 +232,8 @@ TEST_F(CompareNodeTest, ApplyMissingFieldMaxNumber) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 0}}"), fromjson("{$v:2, diff: {i: {a: 0}}}"));
}
TEST_F(CompareNodeTest, ApplyExistingNumberMaxNumber) {
@@ -240,7 +250,8 @@ TEST_F(CompareNodeTest, ApplyExistingNumberMaxNumber) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 2}}"), fromjson("{$v:2, diff: {u: {a: 2}}}"));
}
TEST_F(CompareNodeTest, ApplyExistingDateMaxDate) {
@@ -257,7 +268,9 @@ TEST_F(CompareNodeTest, ApplyExistingDateMaxDate) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {$date: 123123123}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: {$date: 123123123}}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: {$date: 123123123}}}"),
+ fromjson("{$v:2, diff: {u: {a: {$date: 123123123}}}}"));
}
TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxDoc) {
@@ -274,7 +287,8 @@ TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxDoc) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 3}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: {b: 3}}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: {b: 3}}}"), fromjson("{$v:2, diff: {u: {a: {b: 3}}}}"));
}
TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxNumber) {
@@ -291,7 +305,8 @@ TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxNumber) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(CompareNodeTest, ApplyMinRespectsCollation) {
@@ -311,7 +326,8 @@ TEST_F(CompareNodeTest, ApplyMinRespectsCollation) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 'dba'}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 'dba'}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 'dba'}}"), fromjson("{$v:2, diff: {u: {a: 'dba'}}}"));
}
TEST_F(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) {
@@ -332,7 +348,8 @@ TEST_F(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 'dba'}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 'dba'}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 'dba'}}"), fromjson("{$v:2, diff: {u: {a: 'dba'}}}"));
}
TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) {
@@ -353,7 +370,8 @@ TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 'abd'}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 'abd'}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 'abd'}}"), fromjson("{$v:2, diff: {u: {a: 'abd'}}}"));
}
DEATH_TEST_REGEX(CompareNodeTest,
@@ -396,7 +414,8 @@ TEST_F(CompareNodeTest, ApplyIndexesNotAffected) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 1}}"), fromjson("{$v:2, diff: {u: {a: 1}}}"));
}
TEST_F(CompareNodeTest, ApplyNoIndexDataOrLogBuilder) {
diff --git a/src/mongo/db/update/current_date_node_test.cpp b/src/mongo/db/update/current_date_node_test.cpp
index a466de92157..95a1fcb2b9e 100644
--- a/src/mongo/db/update/current_date_node_test.cpp
+++ b/src/mongo/db/update/current_date_node_test.cpp
@@ -42,6 +42,22 @@
namespace mongo {
namespace {
+void assertOplogEntryIsUpdateOfExpectedType(const BSONObj& obj,
+ bool v2LogBuilderUsed,
+ StringData fieldName,
+ BSONType expectedType = BSONType::Date) {
+ if (v2LogBuilderUsed) {
+ ASSERT_EQUALS(obj.nFields(), 2);
+ ASSERT_EQUALS(obj["$v"].numberInt(), 2);
+ ASSERT_EQUALS(obj["diff"]["u"][fieldName].type(), expectedType);
+ } else {
+ ASSERT_EQUALS(obj.nFields(), 1);
+ ASSERT_TRUE(obj["$set"].type() == BSONType::Object);
+ ASSERT_EQUALS(obj["$set"].embeddedObject().nFields(), 1U);
+ ASSERT_EQUALS(obj["$set"][fieldName].type(), expectedType);
+ }
+}
+
using CurrentDateNodeTest = UpdateNodeTest;
using mongo::mutablebson::countChildren;
using mongo::mutablebson::Element;
@@ -142,11 +158,7 @@ TEST_F(CurrentDateNodeTest, ApplyTrue) {
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
+ assertOplogEntryIsUpdateOfExpectedType(getOplogEntry(), v2LogBuilderUsed(), "a");
}
TEST_F(CurrentDateNodeTest, ApplyFalse) {
@@ -166,11 +178,7 @@ TEST_F(CurrentDateNodeTest, ApplyFalse) {
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
+ assertOplogEntryIsUpdateOfExpectedType(getOplogEntry(), v2LogBuilderUsed(), "a");
}
TEST_F(CurrentDateNodeTest, ApplyDate) {
@@ -190,11 +198,7 @@ TEST_F(CurrentDateNodeTest, ApplyDate) {
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
+ assertOplogEntryIsUpdateOfExpectedType(getOplogEntry(), v2LogBuilderUsed(), "a");
}
TEST_F(CurrentDateNodeTest, ApplyTimestamp) {
@@ -214,11 +218,8 @@ TEST_F(CurrentDateNodeTest, ApplyTimestamp) {
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::bsonTimestamp);
- ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::bsonTimestamp);
+ assertOplogEntryIsUpdateOfExpectedType(
+ getOplogEntry(), v2LogBuilderUsed(), "a", BSONType::bsonTimestamp);
}
TEST_F(CurrentDateNodeTest, ApplyFieldDoesNotExist) {
@@ -238,11 +239,14 @@ TEST_F(CurrentDateNodeTest, ApplyFieldDoesNotExist) {
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
+ if (v2LogBuilderUsed()) {
+ ASSERT_EQUALS(getOplogEntry().nFields(), 2);
+ ASSERT_EQUALS(getOplogEntry()["$v"].numberInt(), 2);
+ ASSERT_EQUALS(getOplogEntry()["diff"]["i"]["a"].type(), BSONType::Date);
+ } else {
+ ASSERT_EQUALS(getOplogEntry().nFields(), 1);
+ ASSERT_EQUALS(getOplogEntry()["$set"]["a"].type(), BSONType::Date);
+ }
}
TEST_F(CurrentDateNodeTest, ApplyIndexesNotAffected) {
@@ -258,15 +262,7 @@ TEST_F(CurrentDateNodeTest, ApplyIndexesNotAffected) {
ASSERT_FALSE(result.noop);
ASSERT_FALSE(result.indexesAffected);
- ASSERT_EQUALS(doc.root().countChildren(), 1U);
- ASSERT_TRUE(doc.root()["a"].ok());
- ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
-
- ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
- ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
+ assertOplogEntryIsUpdateOfExpectedType(getOplogEntry(), v2LogBuilderUsed(), "a");
}
TEST_F(CurrentDateNodeTest, ApplyNoIndexDataOrLogBuilder) {
diff --git a/src/mongo/db/update/delta_executor.cpp b/src/mongo/db/update/delta_executor.cpp
index 466e66800f8..c1d4eeb9f1e 100644
--- a/src/mongo/db/update/delta_executor.cpp
+++ b/src/mongo/db/update/delta_executor.cpp
@@ -33,6 +33,7 @@
#include "mongo/bson/mutable/document.h"
#include "mongo/db/update/object_replace_executor.h"
+#include "mongo/db/update/update_oplog_entry_serialization.h"
namespace mongo {
@@ -47,6 +48,7 @@ DeltaExecutor::ApplyResult DeltaExecutor::applyUpdate(
auto result = ObjectReplaceExecutor::applyReplacementUpdate(
std::move(applyParams), postImage, postImageHasId);
result.indexesAffected = applyDiffOutput.indexesAffected;
+ result.oplogEntry = _outputOplogEntry;
return result;
}
-} // namespace mongo \ No newline at end of file
+} // namespace mongo
diff --git a/src/mongo/db/update/delta_executor.h b/src/mongo/db/update/delta_executor.h
index f5bc8c162ca..d3ba6a9c199 100644
--- a/src/mongo/db/update/delta_executor.h
+++ b/src/mongo/db/update/delta_executor.h
@@ -33,6 +33,7 @@
#include "mongo/db/update/document_diff_applier.h"
#include "mongo/db/update/document_diff_serialization.h"
+#include "mongo/db/update/update_oplog_entry_serialization.h"
namespace mongo {
@@ -45,7 +46,9 @@ public:
/**
* Initializes the executor with the diff to apply.
*/
- explicit DeltaExecutor(doc_diff::Diff diff) : _diff(std::move(diff)) {}
+ explicit DeltaExecutor(doc_diff::Diff diff)
+ : _diff(std::move(diff)),
+ _outputOplogEntry(update_oplog_entry::makeDeltaOplogEntry(_diff)) {}
ApplyResult applyUpdate(ApplyParams applyParams) const final;
@@ -57,6 +60,11 @@ public:
private:
doc_diff::Diff _diff;
+
+ // Although the delta executor is only used for applying $v:2 oplog entries on secondaries, it
+ // still needs to produce an oplog entry from the applyUpdate() method so that OpObservers may
+ // handle the event appropriately.
+ BSONObj _outputOplogEntry;
};
} // namespace mongo
diff --git a/src/mongo/db/update/pop_node_test.cpp b/src/mongo/db/update/pop_node_test.cpp
index 1349670365c..b17fe6b189b 100644
--- a/src/mongo/db/update/pop_node_test.cpp
+++ b/src/mongo/db/update/pop_node_test.cpp
@@ -115,7 +115,8 @@ TEST_F(PopNodeTest, NoopWhenFirstPathComponentDoesNotExist) {
ASSERT_TRUE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: [1, 2, 3]}"), doc);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -133,7 +134,8 @@ TEST_F(PopNodeTest, NoopWhenPathPartiallyExists) {
ASSERT_TRUE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {}}"), doc);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b.c}", getModifiedPaths());
}
@@ -151,7 +153,8 @@ TEST_F(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) {
ASSERT_TRUE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.0}", getModifiedPaths());
}
@@ -215,7 +218,7 @@ TEST_F(PopNodeTest, NoopWhenPathContainsAnEmptyArray) {
ASSERT_TRUE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -233,7 +236,9 @@ TEST_F(PopNodeTest, PopsSingleElementFromTheBack) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': []}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: []}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -251,7 +256,9 @@ TEST_F(PopNodeTest, PopsSingleElementFromTheFront) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': []}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: []}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -269,7 +276,9 @@ TEST_F(PopNodeTest, PopsFromTheBackOfMultiElementArray) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [1, 2]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [1, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [1, 2]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [1, 2]}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -287,7 +296,9 @@ TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArray) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [2, 3]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [2, 3]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [2, 3]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [2, 3]}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -305,7 +316,9 @@ TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArrayWithoutAffectingIndexes)
ASSERT_FALSE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [2, 3]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [2, 3]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [2, 3]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [2, 3]}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -322,7 +335,9 @@ TEST_F(PopNodeTest, SucceedsWithNullUpdateIndexData) {
ASSERT_FALSE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [1, 2]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [1, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [1, 2]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [1, 2]}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -414,7 +429,8 @@ TEST_F(PopNodeTest, NoopOnImmutablePathSucceeds) {
ASSERT_TRUE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
diff --git a/src/mongo/db/update/pull_node_test.cpp b/src/mongo/db/update/pull_node_test.cpp
index 4a178b0709d..7231445ecab 100644
--- a/src/mongo/db/update/pull_node_test.cpp
+++ b/src/mongo/db/update/pull_node_test.cpp
@@ -144,7 +144,8 @@ TEST_F(PullNodeTest, TargetNotFound) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullNodeTest, ApplyToStringFails) {
@@ -211,7 +212,8 @@ TEST_F(PullNodeTest, ApplyToMissingElement) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {c: {}}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullNodeTest, ApplyToEmptyArray) {
@@ -228,7 +230,8 @@ TEST_F(PullNodeTest, ApplyToEmptyArray) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullNodeTest, ApplyToArrayMatchingNone) {
@@ -245,7 +248,8 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingNone) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2, 3, 4, 5]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullNodeTest, ApplyToArrayMatchingOne) {
@@ -262,7 +266,9 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingOne) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2, 3]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2, 3]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 2, 3]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [1, 2, 3]}}}"));
}
TEST_F(PullNodeTest, ApplyToArrayMatchingSeveral) {
@@ -279,7 +285,9 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingSeveral) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2, 3, 4, 5]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2, 3, 4, 5]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 2, 3, 4, 5]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [1, 2, 3, 4, 5]}}}"));
}
TEST_F(PullNodeTest, ApplyToArrayMatchingAll) {
@@ -296,7 +304,8 @@ TEST_F(PullNodeTest, ApplyToArrayMatchingAll) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {u: {a: []}}}"));
}
TEST_F(PullNodeTest, ApplyNoIndexDataNoLogBuilder) {
@@ -334,7 +343,9 @@ TEST_F(PullNodeTest, ApplyWithCollation) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['zaa', 'zbb']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['zaa', 'zbb']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['zaa', 'zbb']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['zaa', 'zbb']}}}"));
}
TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectNonStringMatches) {
@@ -354,7 +365,8 @@ TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectNonStringMatches) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [2, 1]}}"), fromjson("{$v: 2, diff: {u: {a: [2, 1]}}}"));
}
TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectRegexMatches) {
@@ -374,7 +386,9 @@ TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectRegexMatches) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['b', 'cb']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['b', 'cb']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['b', 'cb']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['b', 'cb']}}}"));
}
TEST_F(PullNodeTest, ApplyStringLiteralMatchWithCollation) {
@@ -394,7 +408,8 @@ TEST_F(PullNodeTest, ApplyStringLiteralMatchWithCollation) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {u: {a: []}}}"));
}
TEST_F(PullNodeTest, ApplyCollationDoesNotAffectNumberLiteralMatches) {
@@ -414,7 +429,9 @@ TEST_F(PullNodeTest, ApplyCollationDoesNotAffectNumberLiteralMatches) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', 'b', 2, 'c', 'd']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['a', 'b', 2, 'c', 'd']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['a', 'b', 2, 'c', 'd']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['a', 'b', 2, 'c', 'd']}}}"));
}
TEST_F(PullNodeTest, ApplyStringMatchAfterSetCollator) {
@@ -550,7 +567,9 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching1) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [{x: 1}, {x: 2}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [{x: 1}, {x: 2}]}}}}"));
}
TEST_F(PullNodeTest, ApplyComplexDocAndMatching2) {
@@ -567,7 +586,9 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching2) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [{x: 1}, {x: 2}, {z: 'z'}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}, {z: 'z'}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}, {z: 'z'}]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [{x: 1}, {x: 2}, {z: 'z'}]}}}}"));
}
TEST_F(PullNodeTest, ApplyComplexDocAndMatching3) {
@@ -584,7 +605,9 @@ TEST_F(PullNodeTest, ApplyComplexDocAndMatching3) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [{x: 2}, {z: 'z'}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 2}, {z: 'z'}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': [{x: 2}, {z: 'z'}]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: [{x: 2}, {z: 'z'}]}}}}"));
}
TEST_F(PullNodeTest, ApplyFullPredicateWithCollation) {
@@ -605,7 +628,9 @@ TEST_F(PullNodeTest, ApplyFullPredicateWithCollation) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': []}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: []}}}}"));
}
TEST_F(PullNodeTest, ApplyScalarValueMod) {
@@ -622,7 +647,9 @@ TEST_F(PullNodeTest, ApplyScalarValueMod) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2, 2, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2, 2, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [2, 2, 2]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [2, 2, 2]}}}"));
}
TEST_F(PullNodeTest, ApplyObjectValueMod) {
@@ -639,7 +666,9 @@ TEST_F(PullNodeTest, ApplyObjectValueMod) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{x: 1}, {x: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{x: 1}, {x: 1}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [{x: 1}, {x: 1}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [{x: 1}, {x: 1}]}}}"));
}
TEST_F(PullNodeTest, DocumentationExample1) {
@@ -657,8 +686,10 @@ TEST_F(PullNodeTest, DocumentationExample1) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}}"),
- getLogDoc());
+
+ assertOplogEntry(
+ fromjson("{$set: {flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}}"),
+ fromjson("{$v: 2, diff: {u: {flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}}}"));
}
TEST_F(PullNodeTest, DocumentationExample2a) {
@@ -675,7 +706,9 @@ TEST_F(PullNodeTest, DocumentationExample2a) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{votes: [3, 5, 6, 8]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {votes: [3, 5, 6, 8]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {votes: [3, 5, 6, 8]}}"),
+ fromjson("{$v: 2, diff: {u: {votes: [3, 5, 6, 8]}}}"));
}
TEST_F(PullNodeTest, DocumentationExample2b) {
@@ -692,7 +725,9 @@ TEST_F(PullNodeTest, DocumentationExample2b) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{votes: [3, 5, 6]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {votes: [3, 5, 6]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {votes: [3, 5, 6]}}"),
+ fromjson("{$v: 2, diff: {u: {votes: [3, 5, 6]}}}"));
}
TEST_F(PullNodeTest, ApplyPullWithObjectValueToArrayWithNonObjectValue) {
@@ -709,7 +744,8 @@ TEST_F(PullNodeTest, ApplyPullWithObjectValueToArrayWithNonObjectValue) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [2]}}"), fromjson("{$v: 2, diff: {u: {a: [2]}}}"));
}
TEST_F(PullNodeTest, CannotModifyImmutableField) {
@@ -742,7 +778,9 @@ TEST_F(PullNodeTest, SERVER_3988) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{x: 1, y: [2, 3, 4, 'abc']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {y: [2, 3, 4, 'abc']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {y: [2, 3, 4, 'abc']}}"),
+ fromjson("{$v: 2, diff: {u: {y: [2, 3, 4, 'abc']}}}"));
}
} // namespace
diff --git a/src/mongo/db/update/pullall_node_test.cpp b/src/mongo/db/update/pullall_node_test.cpp
index 8309b96e8aa..f0879fff9cb 100644
--- a/src/mongo/db/update/pullall_node_test.cpp
+++ b/src/mongo/db/update/pullall_node_test.cpp
@@ -97,7 +97,8 @@ TEST_F(PullAllNodeTest, TargetNotFound) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullAllNodeTest, TargetArrayElementNotFound) {
@@ -115,7 +116,8 @@ TEST_F(PullAllNodeTest, TargetArrayElementNotFound) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullAllNodeTest, ApplyToNonArrayFails) {
@@ -148,7 +150,9 @@ TEST_F(PullAllNodeTest, ApplyWithSingleNumber) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', {r: 1, b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['a', {r: 1, b: 2}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['a', {r: 1, b: 2}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [\"a\", {r: 1, b: 2}]}}}"));
}
TEST_F(PullAllNodeTest, ApplyNoIndexDataNoLogBuilder) {
@@ -181,7 +185,8 @@ TEST_F(PullAllNodeTest, ApplyWithElementNotPresentInArray) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
}
TEST_F(PullAllNodeTest, ApplyWithWithTwoElements) {
@@ -198,7 +203,9 @@ TEST_F(PullAllNodeTest, ApplyWithWithTwoElements) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{r: 1, b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{r: 1, b: 2}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [{r: 1, b: 2}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [{r: 1, b: 2}]}}}"));
}
TEST_F(PullAllNodeTest, ApplyWithAllArrayElements) {
@@ -215,7 +222,8 @@ TEST_F(PullAllNodeTest, ApplyWithAllArrayElements) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {u: {a: []}}}"));
}
TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsButOutOfOrder) {
@@ -232,7 +240,8 @@ TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsButOutOfOrder) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {u: {a: []}}}"));
}
TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsAndThenSome) {
@@ -249,7 +258,8 @@ TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsAndThenSome) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {u: {a: []}}}"));
}
TEST_F(PullAllNodeTest, ApplyWithCollator) {
@@ -269,7 +279,9 @@ TEST_F(PullAllNodeTest, ApplyWithCollator) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['baz']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['baz']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['baz']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['baz']}}}"));
}
TEST_F(PullAllNodeTest, ApplyAfterSetCollator) {
diff --git a/src/mongo/db/update/push_node_test.cpp b/src/mongo/db/update/push_node_test.cpp
index 92e81014846..1810610c302 100644
--- a/src/mongo/db/update/push_node_test.cpp
+++ b/src/mongo/db/update/push_node_test.cpp
@@ -287,7 +287,8 @@ TEST_F(PushNodeTest, ApplyToEmptyArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {u: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -305,7 +306,8 @@ TEST_F(PushNodeTest, ApplyToEmptyDocument) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {i: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -323,7 +325,9 @@ TEST_F(PushNodeTest, ApplyToArrayWithOneElement) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: 1}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -353,7 +357,9 @@ TEST_F(PushNodeTest, ApplyToDottedPathElement) {
"}"),
doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'choices.first.votes': [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'choices.first.votes': [1]}}"),
+ fromjson("{$v: 2, diff: {schoices: {sfirst: {i: {votes: [1]}}}}}"));
ASSERT_EQUALS("{choices.first.votes}", getModifiedPaths());
}
@@ -371,7 +377,8 @@ TEST_F(PushNodeTest, ApplySimpleEachToEmptyArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {u: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -389,7 +396,8 @@ TEST_F(PushNodeTest, ApplySimpleEachToEmptyDocument) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {i: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -407,7 +415,8 @@ TEST_F(PushNodeTest, ApplyMultipleEachToEmptyDocument) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 2]}}"), fromjson("{$v: 2, diff: {i: {a: [1, 2]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -425,7 +434,9 @@ TEST_F(PushNodeTest, ApplySimpleEachToArrayWithOneElement) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: 1}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -443,7 +454,9 @@ TEST_F(PushNodeTest, ApplyMultipleEachToArrayWithOneElement) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 1, 'a.2': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': 1, 'a.2': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: 1, u2: 2}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -461,7 +474,8 @@ TEST_F(PushNodeTest, ApplyEmptyEachToEmptyArray) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -479,7 +493,8 @@ TEST_F(PushNodeTest, ApplyEmptyEachToEmptyDocument) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: []}}"), fromjson("{$v: 2, diff: {i: {a: []}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -497,7 +512,8 @@ TEST_F(PushNodeTest, ApplyEmptyEachToArrayWithOneElement) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -515,7 +531,8 @@ TEST_F(PushNodeTest, ApplyToArrayWithSlice) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [3]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [3]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [3]}}"), fromjson("{$v: 2, diff: {u: {a: [3]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -533,7 +550,9 @@ TEST_F(PushNodeTest, ApplyWithNumericSort) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [-1, 2, 3]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [-1, 2, 3]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [-1, 2, 3]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [-1, 2, 3]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -551,7 +570,9 @@ TEST_F(PushNodeTest, ApplyWithReverseNumericSort) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [4, 3, -1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [4, 3, -1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [4, 3, -1]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [4, 3, -1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -569,7 +590,9 @@ TEST_F(PushNodeTest, ApplyWithMixedSort) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [-1, 3, 4, 't', {a: 1}, {b: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [-1, 3, 4, 't', {a: 1}, {b: 1}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [-1, 3, 4, 't', {a: 1}, {b: 1}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [-1, 3, 4, 't', {a: 1}, {b: 1}]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -587,7 +610,9 @@ TEST_F(PushNodeTest, ApplyWithReverseMixedSort) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 1}, {a: 1}, 't', 4, 3, -1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{b: 1}, {a: 1}, 't', 4, 3, -1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [{b: 1}, {a: 1}, 't', 4, 3, -1]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [{b: 1}, {a: 1}, 't', 4, 3, -1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -605,7 +630,9 @@ TEST_F(PushNodeTest, ApplyWithEmbeddedFieldSort) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [3, 't', {b: 1}, 4, -1, {a: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [3, 't', {b: 1}, 4, -1, {a: 1}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [3, 't', {b: 1}, 4, -1, {a: 1}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [3, 't', {b: 1}, 4, -1, {a: 1}]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -626,7 +653,9 @@ TEST_F(PushNodeTest, ApplySortWithCollator) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['ha', 'gb', 'fc', 'dd']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['ha', 'gb', 'fc', 'dd']}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: ['ha', 'gb', 'fc', 'dd']}}"),
+ fromjson("{$v: 2, diff: {u: {a: ['ha', 'gb', 'fc', 'dd']}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -855,7 +884,8 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithPositionZero) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {u: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -873,7 +903,8 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithPositionOne) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {u: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -891,7 +922,8 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithLargePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {u: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -909,7 +941,8 @@ TEST_F(PushNodeTest, ApplyToSingletonArrayWithPositionZero) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 0]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 0]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 0]}}"), fromjson("{$v: 2, diff: {u: {a: [1, 0]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -927,7 +960,9 @@ TEST_F(PushNodeTest, ApplyToSingletonArrayWithLargePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': 1}}"),
+ fromjson(" {$v: 2, diff: {sa: {a: true, u1: 1}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -945,7 +980,8 @@ TEST_F(PushNodeTest, ApplyToEmptyArrayWithNegativePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1]}}"), fromjson("{$v: 2, diff: {u: {a: [1]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -963,7 +999,8 @@ TEST_F(PushNodeTest, ApplyToSingletonArrayWithNegativePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 0]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 0]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 0]}}"), fromjson("{$v: 2, diff: {u: {a: [1, 0]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -981,7 +1018,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithNegativePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1, 2, 5, 3, 4]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1, 2, 5, 3, 4]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1, 2, 5, 3, 4]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [0, 1, 2, 5, 3, 4]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -999,7 +1038,9 @@ TEST_F(PushNodeTest, ApplyToPopulatedArrayWithOutOfBoundsNegativePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [5, 0, 1, 2, 3, 4]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [5, 0, 1, 2, 3, 4]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [5, 0, 1, 2, 3, 4]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [5, 0, 1, 2, 3, 4]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1017,7 +1058,9 @@ TEST_F(PushNodeTest, ApplyMultipleElementsPushWithNegativePosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1, 2, 5, 6, 7, 3, 4]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1, 2, 5, 6, 7, 3, 4]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [0, 1, 2, 5, 6, 7, 3, 4]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [0, 1, 2, 5, 6, 7, 3, 4]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1037,7 +1080,9 @@ TEST_F(PushNodeTest, PushWithMinIntAsPosition) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [5, 0, 1, 2, 3, 4]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [5, 0, 1, 2, 3, 4]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [5, 0, 1, 2, 3, 4]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [5, 0, 1, 2, 3, 4]}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
diff --git a/src/mongo/db/update/rename_node_test.cpp b/src/mongo/db/update/rename_node_test.cpp
index bc52481b036..1ac12e6254d 100644
--- a/src/mongo/db/update/rename_node_test.cpp
+++ b/src/mongo/db/update/rename_node_test.cpp
@@ -123,7 +123,9 @@ TEST_F(RenameNodeTest, SimpleNumberAtRoot) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: 2}, $unset: {a: true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, i: {b: 2}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -140,7 +142,9 @@ TEST_F(RenameNodeTest, ToExistsAtSameLevel) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: 2}, $unset: {a: true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, u: {b: 2}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -157,7 +161,9 @@ TEST_F(RenameNodeTest, ToAndFromHaveSameValue) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: 2}, $unset: {a: true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, u: {b: 2}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -174,7 +180,9 @@ TEST_F(RenameNodeTest, RenameToFieldWithSameValueButDifferentType) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 1}, $unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: 1}, $unset: {a: true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, u: {b: 1}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -191,7 +199,9 @@ TEST_F(RenameNodeTest, FromDottedElement) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {}, b: {d: 6}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: {d: 6}}, $unset: {'a.c': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: {d: 6}}, $unset: {'a.c': true}}"),
+ fromjson("{$v: 2, diff: {u: {b: {d: 6}}, sa: {d: {c: false}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.c, b}");
}
@@ -208,7 +218,9 @@ TEST_F(RenameNodeTest, RenameToExistingNestedFieldDoesNotReorderFields) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {c: 4, d: 2}}, b: 3, c: {}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 4}, $unset: {'c.d': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b.c': 4}, $unset: {'c.d': true}}"),
+ fromjson("{$v: 2, diff: {sa: {sb: {u: {c: 4}}}, sc: {d: {d: false}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b.c, c.d}");
}
@@ -226,7 +238,9 @@ TEST_F(RenameNodeTest, MissingCompleteTo) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1, c: {r: {d: 2}}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'c.r.d': 2}, $unset: {'a': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'c.r.d': 2}, $unset: {'a': true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, sc: {i: {r: {d: 2}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, c.r.d}");
}
@@ -243,7 +257,9 @@ TEST_F(RenameNodeTest, ToIsCompletelyMissing) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: {c: {d: 2}}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'b.c.d': 2}, $unset: {'a': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'b.c.d': 2}, $unset: {'a': true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, i: {b: {c: {d: 2}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b.c.d}");
}
@@ -260,7 +276,9 @@ TEST_F(RenameNodeTest, ToMissingDottedField) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: {c: {d: [{a:2, b:1}]}}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'b.c.d': [{a:2, b:1}]}, $unset: {'a': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'b.c.d': [{a:2, b:1}]}, $unset: {'a': true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, i: {b: {c: {d: [{a: 2, b: 1}]}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b.c.d}");
}
@@ -378,7 +396,9 @@ TEST_F(RenameNodeTest, ReplaceArrayField) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: 2}, $unset: {a: true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, u: {b: 2}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -395,7 +415,9 @@ TEST_F(RenameNodeTest, ReplaceWithArrayField) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: []}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: []}, $unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: []}, $unset: {a: true}}"),
+ fromjson("{$v: 2, diff: {d: {a: false}, u: {b: []}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -412,7 +434,9 @@ TEST_F(RenameNodeTest, CanRenameFromInvalidFieldName) {
ASSERT_FALSE(result.noop);
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {a: 2}, $unset: {'$a': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 2}, $unset: {'$a': true}}"),
+ fromjson("{$v: 2, diff: {d: {$a: false}, i: {a: 2}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{$a, a}");
}
@@ -443,7 +467,8 @@ TEST_F(RenameNodeTest, RenameFromNonExistentPathIsNoOp) {
ASSERT_TRUE(result.noop);
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a, b}");
}
@@ -479,7 +504,9 @@ TEST_F(RenameNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFa
<< "b" << 0);
ASSERT_EQUALS(updated, doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'b': 0}, $unset: {'a.$id': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'b': 0}, $unset: {'a.$id': true}}"),
+ fromjson("{$v: 2, diff: {i: {b: 0}, sa: {d: {$id: false}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.$id, b}");
}
@@ -546,7 +573,8 @@ TEST_F(RenameNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a.b.c, d}");
}
diff --git a/src/mongo/db/update/set_node_test.cpp b/src/mongo/db/update/set_node_test.cpp
index 45198f6e179..55a7f54027d 100644
--- a/src/mongo/db/update/set_node_test.cpp
+++ b/src/mongo/db/update/set_node_test.cpp
@@ -74,7 +74,8 @@ TEST_F(SetNodeTest, ApplyNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -92,7 +93,8 @@ TEST_F(SetNodeTest, ApplyEmptyPathToCreate) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 6}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 6}}"), fromjson("{$v: 2, diff: {u: {a: 6}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -111,7 +113,9 @@ TEST_F(SetNodeTest, ApplyCreatePath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {d: 5, b: {c: 6}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b.c': 6}}"),
+ fromjson("{$v: 2, diff: {sa: {i: {b: {c: 6}}}}}"));
ASSERT_EQUALS("{a.b.c}", getModifiedPaths());
}
@@ -129,7 +133,8 @@ TEST_F(SetNodeTest, ApplyCreatePathFromRoot) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{c: 5, a: {b: 6}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 6}}"), fromjson("{$v: 2, diff: {i: {a: {b: 6}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -148,7 +153,9 @@ TEST_F(SetNodeTest, ApplyPositional) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 6, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': 6}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: 6}}}"));
ASSERT_EQUALS("{a.1}", getModifiedPaths());
}
@@ -185,7 +192,8 @@ TEST_F(SetNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -357,8 +365,8 @@ TEST_F(SetNodeTest, ApplyLog) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 2}}"), fromjson("{$v: 2, diff: {u: {a: 2}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -757,8 +765,9 @@ TEST_F(SetNodeTest, ApplyLogDottedPath) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: [{b:0}, {b:1}, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: {b: 2}}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -774,8 +783,9 @@ TEST_F(SetNodeTest, LogEmptyArray) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: [null, null, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: {b: 2}}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -791,8 +801,9 @@ TEST_F(SetNodeTest, LogEmptyObject) {
node.apply(getApplyParams(doc.root()["a"]), getUpdateNodeApplyParams());
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {i: {'2': {b: 2}}}}}"));
ASSERT_EQUALS("{a.2.b}", getModifiedPaths());
}
@@ -974,8 +985,8 @@ TEST_F(SetNodeTest, Set6) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 1, r: {a:2, b:2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'r.a': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'r.a': 2}}"), fromjson("{$v: 2, diff: {sr: {u: {a: 2}}}}"));
ASSERT_EQUALS("{r.a}", getModifiedPaths());
}
@@ -994,8 +1005,8 @@ TEST_F(SetNodeTest, Set6FromRepl) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 1, r: {a:2, b:2} }"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'r.a': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'r.a': 2}}"), fromjson("{$v: 2, diff: {sr: {u: {a: 2}}}}"));
ASSERT_EQUALS("{r.a}", getModifiedPaths());
}
@@ -1098,8 +1109,8 @@ TEST_F(SetNodeTest, ApplyCanCreateDollarPrefixedFieldNameWhenValidateForStorageI
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{$bad: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {$bad: 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {$bad: 1}}"), fromjson("{$v: 2, diff: {i: {$bad: 1}}}"));
ASSERT_EQUALS("{$bad}", getModifiedPaths());
}
@@ -1134,8 +1145,8 @@ TEST_F(SetNodeTest, ApplyCanPerformNoopOnImmutablePath) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 0u);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -1187,8 +1198,8 @@ TEST_F(SetNodeTest, ApplyCanPerformNoopOnPrefixOfImmutablePath) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 0u);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1207,8 +1218,8 @@ TEST_F(SetNodeTest, ApplyCanOverwritePrefixToCreateImmutablePath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: {b: 2}}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: {b: 2}}}"), fromjson("{$v: 2, diff: {u: {a: {b: 2}}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1227,8 +1238,9 @@ TEST_F(SetNodeTest, ApplyCanOverwritePrefixOfImmutablePathIfNoopOnImmutablePath)
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2, c: 3}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: {b: 2, c: 3}}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: {b: 2, c: 3}}}"),
+ fromjson("{$v: 2, diff: {u: {a: {b: 2, c: 3}}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1263,8 +1275,8 @@ TEST_F(SetNodeTest, ApplyCanPerformNoopOnSuffixOfImmutablePath) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {c: 2}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 0u);
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.b.c}", getModifiedPaths());
}
@@ -1318,8 +1330,8 @@ TEST_F(SetNodeTest, ApplyCanCreateImmutablePath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 2}}"), fromjson("{$v: 2, diff: {sa: {i: {b: 2}}}}"));
ASSERT_EQUALS("{a.b}", getModifiedPaths());
}
@@ -1338,8 +1350,8 @@ TEST_F(SetNodeTest, ApplyCanCreatePrefixOfImmutablePath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 2}}"), fromjson("{$v: 2, diff: {i: {a: 2}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1358,8 +1370,9 @@ TEST_F(SetNodeTest, ApplySetFieldInNonExistentArrayElementAffectsIndexOnSiblingF
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0}, {c: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.1.c': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1.c': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: {c: 2}}}}"));
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -1378,8 +1391,9 @@ TEST_F(SetNodeTest, ApplySetFieldInExistingArrayElementDoesNotAffectIndexOnSibli
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0, c: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.0.c': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.c': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {i: {c: 2}}}}}"));
ASSERT_EQUALS("{a.0.c}", getModifiedPaths());
}
@@ -1399,8 +1413,9 @@ TEST_F(SetNodeTest, ApplySetFieldInNonExistentNumericFieldDoesNotAffectIndexOnSi
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'0': {b: 0}, '1': {c: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.1.c': 2}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1.c': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {i: {'1': {c: 2}}}}}"));
ASSERT_EQUALS("{a.1.c}", getModifiedPaths());
}
@@ -1418,7 +1433,8 @@ TEST_F(SetNodeTest, ApplySetOnInsertIsNoopWhenInsertIsFalse) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
diff --git a/src/mongo/db/update/unset_node.cpp b/src/mongo/db/update/unset_node.cpp
index d49b5492cd3..c731833cfce 100644
--- a/src/mongo/db/update/unset_node.cpp
+++ b/src/mongo/db/update/unset_node.cpp
@@ -86,7 +86,14 @@ void UnsetNode::logUpdate(LogBuilderInterface* logBuilder,
invariant(logBuilder);
invariant(modifyResult == ModifyResult::kNormalUpdate);
invariant(!createdFieldIdx);
- uassertStatusOK(logBuilder->logDeletedField(pathTaken));
+
+ if (pathTaken.types().back() == RuntimeUpdatePath::ComponentType::kArrayIndex) {
+ // If $unset is applied to an array index, the value was set to null.
+ invariant(element.getType() == BSONType::jstNULL);
+ uassertStatusOK(logBuilder->logUpdatedField(pathTaken, element));
+ } else {
+ uassertStatusOK(logBuilder->logDeletedField(pathTaken));
+ }
}
} // namespace mongo
diff --git a/src/mongo/db/update/unset_node_test.cpp b/src/mongo/db/update/unset_node_test.cpp
index 67cb1140856..d45b2472a90 100644
--- a/src/mongo/db/update/unset_node_test.cpp
+++ b/src/mongo/db/update/unset_node_test.cpp
@@ -89,7 +89,8 @@ TEST_F(UnsetNodeTest, UnsetNoOp) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -108,7 +109,8 @@ TEST_F(UnsetNodeTest, UnsetNoOpDottedPath) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -127,7 +129,8 @@ TEST_F(UnsetNodeTest, UnsetNoOpThroughArray) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a:[{b:1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -145,7 +148,8 @@ TEST_F(UnsetNodeTest, UnsetNoOpEmptyDoc) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -163,7 +167,8 @@ TEST_F(UnsetNodeTest, UnsetTopLevelPath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {a: true}}"), fromjson("{$v: 2, diff: {d: {a: false}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -181,7 +186,9 @@ TEST_F(UnsetNodeTest, UnsetNestedPath) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.b.c': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {'a.b.c': true}}"),
+ fromjson("{$v: 2, diff: {sa: {sb: {d: {c: false}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b.c}");
}
@@ -199,7 +206,9 @@ TEST_F(UnsetNodeTest, UnsetObject) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.b': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {'a.b': true}}"),
+ fromjson("{$v: 2, diff: {sa: {d: {b: false}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -217,7 +226,9 @@ TEST_F(UnsetNodeTest, UnsetArrayElement) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a:[null], b:1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.0': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.0': null}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u0: null}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0}");
}
@@ -236,7 +247,9 @@ TEST_F(UnsetNodeTest, UnsetPositional) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, null, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.1': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': null}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: null}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.1}");
}
@@ -254,7 +267,8 @@ TEST_F(UnsetNodeTest, UnsetEntireArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {a: true}}"), fromjson("{$v: 2, diff: {d: {a: false}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -272,7 +286,9 @@ TEST_F(UnsetNodeTest, UnsetFromObjectInArray) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a:[{}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.0.b': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {'a.0.b': true}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {d: {b: false}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.b}");
}
@@ -290,7 +306,9 @@ TEST_F(UnsetNodeTest, CanUnsetInvalidField) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1, a: [{}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.0.$b': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {'a.0.$b': true}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {d: {$b: false}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.$b}");
}
@@ -325,7 +343,8 @@ TEST_F(UnsetNodeTest, ApplyDoesNotAffectIndexes) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {a: true}}"), fromjson("{$v: 2, diff: {d: {a: false}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -343,7 +362,9 @@ TEST_F(UnsetNodeTest, ApplyFieldWithDot) {
ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{'a.b':4, a: {}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.b': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {'a.b': true}}"),
+ fromjson("{$v: 2, diff: {sa: {d: {b: false}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
@@ -379,7 +400,9 @@ TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFal
<< "c"));
ASSERT_EQUALS(updated, doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.$id': true}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$unset: {'a.$id': true}}"),
+ fromjson("{$v: 2, diff: {sa: {d: {$id: false}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.$id}");
}
@@ -447,7 +470,8 @@ TEST_F(UnsetNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 1}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a.b.c}");
}
diff --git a/src/mongo/db/update/update_array_node_test.cpp b/src/mongo/db/update/update_array_node_test.cpp
index d35a3a44633..95dbf2356a7 100644
--- a/src/mongo/db/update/update_array_node_test.cpp
+++ b/src/mongo/db/update/update_array_node_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/pipeline/expression_context_for_test.h"
#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/db/update/update_object_node.h"
+#include "mongo/unittest/bson_test_util.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
@@ -120,7 +121,9 @@ TEST_F(UpdateArrayNodeTest, UpdateIsAppliedToAllMatchingElements) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [2, 1, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2, 1, 2]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [2, 1, 2]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [2, 1, 2]}}}"));
ASSERT_EQUALS("{a.0, a.2}", getModifiedPaths());
}
@@ -169,7 +172,9 @@ TEST_F(UpdateArrayNodeTest, UpdateForEmptyIdentifierIsAppliedToAllArrayElements)
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [1, 1, 1]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 1, 1]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [1, 1, 1]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [1, 1, 1]}}}"));
ASSERT_EQUALS("{a.0, a.1, a.2}", getModifiedPaths());
}
@@ -217,7 +222,9 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElement) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 1, c: 1, d: 1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1, 'a.0.d': 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1, 'a.0.d': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 1, c: 1, d: 1}}}}}"));
ASSERT_EQUALS("{a.0.b, a.0.c, a.0.d}", getModifiedPaths());
}
@@ -256,7 +263,9 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsUsingMergedChildr
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 1, c: 1}, {b: 1, c: 1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{b: 1, c: 1}, {b: 1, c: 1}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [{b: 1, c: 1}, {b: 1, c: 1}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [{b: 1, c: 1}, {b: 1, c: 1}]}}}"));
ASSERT_EQUALS("{a.0.b, a.0.c, a.1.b, a.1.c}", getModifiedPaths());
}
@@ -304,7 +313,9 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsWithoutMergedChil
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}}}"));
ASSERT_EQUALS("{a.0.b, a.0.c, a.1.c, a.1.d}", getModifiedPaths());
}
@@ -334,7 +345,9 @@ TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementWithEmptyIdentifie
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 1, c: 1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 1, c: 1}}}}}"));
ASSERT_EQUALS("{a.0.b, a.0.c}", getModifiedPaths());
}
@@ -379,7 +392,10 @@ TEST_F(UpdateArrayNodeTest, ApplyNestedArrayUpdates) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{x: 0, b: [{c: 1, d: 1}]}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b.0.c': 1, 'a.0.b.0.d': 1}}"), getLogDoc());
+
+ assertOplogEntry(
+ fromjson("{$set: {'a.0.b.0.c': 1, 'a.0.b.0.d': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {sb: {a: true, s0: {u: {c: 1, d: 1}}}}}}}"));
ASSERT_EQUALS("{a.0.b.0.c, a.0.b.0.d}", getModifiedPaths());
}
@@ -520,7 +536,8 @@ TEST_F(UpdateArrayNodeTest, NoArrayElementsMatch) {
ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: [2, 2, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -547,7 +564,8 @@ TEST_F(UpdateArrayNodeTest, UpdatesToAllArrayElementsAreNoops) {
ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: [1, 1, 1]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.0, a.1, a.2}", getModifiedPaths());
}
@@ -574,7 +592,10 @@ TEST_F(UpdateArrayNodeTest, NoArrayElementAffectsIndexes) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}}"), getLogDoc());
+
+ assertOplogEntry(
+ fromjson("{$set: {a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}}"),
+ fromjson("{$v: 2, diff: {u: {a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}}}"));
ASSERT_EQUALS("{a.0.b, a.1.b, a.2.b}", getModifiedPaths());
}
@@ -601,7 +622,9 @@ TEST_F(UpdateArrayNodeTest, WhenOneElementIsMatchedLogElementUpdateDirectly) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{c: 1}, {c: 0, b: 0}, {c: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1.b': 0}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1.b': 0}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s1: {i: {b: 0}}}}}"));
ASSERT_EQUALS("{a.1.b}", getModifiedPaths());
}
@@ -628,7 +651,9 @@ TEST_F(UpdateArrayNodeTest, WhenOneElementIsModifiedLogElement) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': {c: 0, b: 0}}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.1': {c: 0, b: 0}}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u1: {c: 0, b: 0}}}}"));
ASSERT_EQUALS("{a.0.b, a.1.b}", getModifiedPaths());
}
@@ -652,7 +677,8 @@ TEST_F(UpdateArrayNodeTest, ArrayUpdateOnEmptyArrayIsANoop) {
ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a}", getModifiedPaths());
}
@@ -680,7 +706,9 @@ TEST_F(UpdateArrayNodeTest, ApplyPositionalInsideArrayUpdate) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: [0, 1], c: 0}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b.1': 1}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.b.1': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {sb: {a: true, u1: 1}}}}}"));
ASSERT_EQUALS("{a.0.b.1}", getModifiedPaths());
}
@@ -708,7 +736,8 @@ TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateFromReplication) {
ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), getLogDoc());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS("{a.0.b}", getModifiedPaths());
}
diff --git a/src/mongo/db/update/update_node_test_fixture.h b/src/mongo/db/update/update_node_test_fixture.h
index aa4721894b4..aaa72fe2545 100644
--- a/src/mongo/db/update/update_node_test_fixture.h
+++ b/src/mongo/db/update/update_node_test_fixture.h
@@ -34,6 +34,7 @@
#include "mongo/db/service_context_test_fixture.h"
#include "mongo/db/update/update_node.h"
#include "mongo/db/update/v1_log_builder.h"
+#include "mongo/db/update/v2_log_builder.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -42,6 +43,13 @@ class UpdateNodeTest : public ServiceContextTest {
public:
~UpdateNodeTest() override = default;
+ void run() {
+ _useV2LogBuilder = false;
+ ServiceContextTest::run();
+ _useV2LogBuilder = true;
+ ServiceContextTest::run();
+ }
+
protected:
// Creates a RuntimeUpdatePath from a string, assuming that all numeric path components are
// array indexes. Tests which use numeric field names in objects must manually create a
@@ -79,7 +87,11 @@ protected:
_validateForStorage = true;
_indexData.reset();
_logDoc.reset();
- _logBuilder = std::make_unique<V1LogBuilder>(_logDoc.root());
+ if (_useV2LogBuilder) {
+ _logBuilder = std::make_unique<v2_log_builder::V2LogBuilder>();
+ } else {
+ _logBuilder = std::make_unique<V1LogBuilder>(_logDoc.root());
+ }
_modifiedPaths.clear();
}
@@ -145,14 +157,44 @@ protected:
_logBuilder.reset();
}
- const mutablebson::Document& getLogDoc() {
- return _logDoc;
- }
-
std::string getModifiedPaths() {
return _modifiedPaths.toString();
}
+ bool v2LogBuilderUsed() const {
+ return _useV2LogBuilder;
+ }
+
+ BSONObj getOplogEntry() const {
+ return _logBuilder->serialize();
+ }
+
+ void assertOplogEntryIsNoop() const {
+ if (v2LogBuilderUsed()) {
+ ASSERT_BSONOBJ_BINARY_EQ(getOplogEntry(), fromjson("{$v:2, diff: {}}"));
+ } else {
+ ASSERT_TRUE(getOplogEntry().isEmpty());
+ }
+ }
+
+ void assertOplogEntry(const BSONObj& expectedV1Entry,
+ const BSONObj& expectedV2Entry,
+ bool checkBinaryEquality = true) {
+ auto assertFn = [checkBinaryEquality](auto expected, auto given) {
+ if (checkBinaryEquality) {
+ ASSERT_BSONOBJ_BINARY_EQ(expected, given);
+ } else {
+ ASSERT_BSONOBJ_EQ(expected, given);
+ }
+ };
+
+ if (v2LogBuilderUsed()) {
+ assertFn(expectedV2Entry, getOplogEntry());
+ } else {
+ assertFn(expectedV1Entry, getOplogEntry());
+ }
+ }
+
private:
std::vector<std::unique_ptr<FieldRef>> _immutablePathsVector;
FieldRefSet _immutablePaths;
@@ -166,6 +208,8 @@ private:
mutablebson::Document _logDoc;
std::unique_ptr<LogBuilderInterface> _logBuilder;
FieldRefSetWithStorage _modifiedPaths;
+
+ bool _useV2LogBuilder = false;
};
} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node_test.cpp b/src/mongo/db/update/update_object_node_test.cpp
index e1c0282eaab..a8d09f4f891 100644
--- a/src/mongo/db/update/update_object_node_test.cpp
+++ b/src/mongo/db/update/update_object_node_test.cpp
@@ -1774,7 +1774,8 @@ TEST_F(UpdateObjectNodeTest, ApplyCreateField) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 5, b: 6}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {b: 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {b: 6}}"), fromjson("{$v: 2, diff: {i: {b: 6}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{b}");
}
@@ -1798,7 +1799,8 @@ TEST_F(UpdateObjectNodeTest, ApplyExistingField) {
ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 6}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 6}}"), getLogDoc());
+
+ assertOplogEntry(fromjson("{$set: {a: 6}}"), fromjson("{$v: 2, diff: {u: {a: 6}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -1840,7 +1842,9 @@ TEST_F(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 5, c: 7, b: 6, d: 8}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}"),
+ fromjson("{$v: 2, diff: {u: {a: 5, c: 7}, i: {b: 6, d: 8}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b, c, d}");
}
@@ -1882,8 +1886,9 @@ TEST_F(UpdateObjectNodeTest, ApplyExistingNestedPaths) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {b: 6, c: 7}, b: {d: 8, e: 9}}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"),
- getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: 6, c: 7}}, sb: {u: {d: 8, e: 9}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b, a.c, b.d, b.e}");
}
@@ -1925,8 +1930,9 @@ TEST_F(UpdateObjectNodeTest, ApplyCreateNestedPaths) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{z: 0, a: {b: 6, c: 7}, b: {d: 8, e: 9}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"),
- getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"),
+ fromjson("{$v: 2, diff: {i: {a: {b: 6, c: 7}, b: {d: 8, e: 9}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b, a.c, b.d, b.e}");
}
@@ -1962,8 +1968,9 @@ TEST_F(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{z: 0, a: {b: {c: {d: 6, e: 7}}, f: 8}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b.c.d': 6, 'a.b.c.e': 7, 'a.f': 8}}"),
- getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.b.c.d': 6, 'a.b.c.e': 7, 'a.f': 8}}"),
+ fromjson("{$v: 2, diff: {i: {a: {b: {c: {d: 6, e: 7}}, f: 8}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b.c.d, a.b.c.e, a.f}");
}
@@ -2011,7 +2018,9 @@ TEST_F(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{z: 9, a: 5, b: 8, c: 7, d: 6}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {a: 5, b: 8, c: 7, d: 6, z: 9}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {a: 5, b: 8, c: 7, d: 6, z: 9}}"),
+ fromjson("{$v: 2, diff: {u: {a: 5, z: 9}, i: {b: 8, c: 7, d: 6}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b, c, d, z}");
}
@@ -2044,7 +2053,9 @@ TEST_F(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{abc: 5, cba: 6}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {abc: 5, cba: 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {abc: 5, cba: 6}}"),
+ fromjson("{$v: 2, diff: {i: {abc: 5, cba: 6}}}"));
}
TEST_F(UpdateObjectNodeTest, ApplyNoop) {
@@ -2081,7 +2092,8 @@ TEST_F(UpdateObjectNodeTest, ApplyNoop) {
ASSERT_TRUE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 5, b: 6, c: 7}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{}"), getLogDoc().getObject());
+
+ assertOplogEntryIsNoop();
ASSERT_EQUALS(getModifiedPaths(), "{a, b, c}");
}
@@ -2119,7 +2131,8 @@ TEST_F(UpdateObjectNodeTest, ApplySomeChildrenNoops) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 5, b: 6, c: 7}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {b: 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {b: 6}}"), fromjson("{$v: 2, diff: {u: {b: 6}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a, b, c}");
}
@@ -2172,7 +2185,8 @@ TEST_F(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 0, b: 6}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {b: 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {b: 6}}"), fromjson("{$v: 2, diff: {i: {b: 6}}}"));
}
TEST_F(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) {
@@ -2225,7 +2239,9 @@ TEST_F(UpdateObjectNodeTest, ApplyMergePositionalChild) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 5, c: 6}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.b, a.0.c}");
}
@@ -2268,8 +2284,9 @@ TEST_F(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {'0': 7, '1': {b: 6, c: 8}, '2': 5}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 7, 'a.1.b': 6, 'a.1.c': 8, 'a.2': 5}}"),
- getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.0': 7, 'a.1.b': 6, 'a.1.c': 8, 'a.2': 5}}"),
+ fromjson("{$v: 2, diff: {i: {a: {'0': 7, '1': {b: 6, c: 8}, '2': 5}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0, a.1.b, a.1.c, a.2}");
}
@@ -2335,7 +2352,9 @@ TEST_F(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {'0': 5, '1': 7, '2': 6}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 5, 'a.1': 7, 'a.2': 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.0': 5, 'a.1': 7, 'a.2': 6}}"),
+ fromjson("{$v: 2, diff: {i: {a: {'0': 5, '1': 7, '2': 6}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0, a.1, a.2}");
}
@@ -2372,7 +2391,9 @@ TEST_F(UpdateObjectNodeTest, ApplyPositionalChildLast) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {'0': 6, '1': 7, '2': 5}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 6, 'a.1': 7, 'a.2': 5}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.0': 6, 'a.1': 7, 'a.2': 5}}"),
+ fromjson("{$v: 2, diff: {i: {a: {'0': 6, '1': 7, '2': 5}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0, a.1, a.2}");
}
@@ -2403,7 +2424,9 @@ TEST_F(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 5, c: 6}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.b, a.0.c}");
mutablebson::Document doc2(fromjson("{a: [{b: 0, c: 0}]}"));
@@ -2415,7 +2438,9 @@ TEST_F(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}]}"), doc2.getObject());
ASSERT_TRUE(doc2.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 5, c: 6}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.b, a.0.c}");
}
@@ -2452,8 +2477,10 @@ TEST_F(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}, {c: 0, d: 7}]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6, 'a.1.d': 7}}"),
- getLogDoc().getObject());
+
+ assertOplogEntry(
+ fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6, 'a.1.d': 7}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 5, c: 6}}, s1: {u: {d: 7}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.b, a.0.c, a.1.d}");
mutablebson::Document doc2(fromjson("{a: [{b: 0, c: 0}, {c: 0, d: 0}]}"));
@@ -2465,8 +2492,10 @@ TEST_F(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 0}, {c: 6, d: 7}]}"), doc2.getObject());
ASSERT_TRUE(doc2.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.1.c': 6, 'a.1.d': 7}}"),
- getLogDoc().getObject());
+
+ assertOplogEntry(
+ fromjson("{$set: {'a.0.b': 5, 'a.1.c': 6, 'a.1.d': 7}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, s0: {u: {b: 5}}, s1: {u: {c: 6, d: 7}}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.0.b, a.1.c, a.1.d}");
}
@@ -2495,7 +2524,9 @@ TEST_F(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [0, 0, 2, 0, 0]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.02': 2}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.02': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: 2}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.02}");
}
@@ -2533,7 +2564,9 @@ TEST_F(UpdateObjectNodeTest, ApplyMultipleArrayUpdates) {
fromjson("{a: [null, null, 2, null, null, null, null, null, null, null, 10]}"),
doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.10': 10, 'a.2': 2}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.10': 10, 'a.2': 2}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: 2, u10: 10}}}"));
}
TEST_F(UpdateObjectNodeTest, ApplyMultipleUpdatesToDocumentInArray) {
@@ -2562,7 +2595,9 @@ TEST_F(UpdateObjectNodeTest, ApplyMultipleUpdatesToDocumentInArray) {
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [null, null, {b: 1, c: 1}]}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.2.b': 1, 'a.2.c': 1}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.2.b': 1, 'a.2.c': 1}}"),
+ fromjson("{$v: 2, diff: {sa: {a: true, u2: {b: 1, c: 1}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
@@ -2612,7 +2647,9 @@ TEST_F(UpdateObjectNodeTest, SetAndPopModifiersWithCommonPrefixApplySuccessfully
ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {b: 5, c: [2, 3, 4]}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 5, 'a.c': [2, 3, 4]}}"), getLogDoc().getObject());
+
+ assertOplogEntry(fromjson("{$set: {'a.b': 5, 'a.c': [2, 3, 4]}}"),
+ fromjson("{$v: 2, diff: {sa: {u: {b: 5, c: [ 2, 3, 4 ]}}}}"));
ASSERT_EQUALS(getModifiedPaths(), "{a.b, a.c}");
}
diff --git a/src/mongo/db/update/update_tree_executor.h b/src/mongo/db/update/update_tree_executor.h
index fff31d4935f..e9f7dc93f99 100644
--- a/src/mongo/db/update/update_tree_executor.h
+++ b/src/mongo/db/update/update_tree_executor.h
@@ -34,6 +34,7 @@
#include "mongo/db/update/update_node.h"
#include "mongo/db/update/update_object_node.h"
#include "mongo/db/update/v1_log_builder.h"
+#include "mongo/db/update/v2_log_builder.h"
namespace mongo {
@@ -44,11 +45,12 @@ public:
ApplyResult applyUpdate(ApplyParams applyParams) const final {
mutablebson::Document logDocument;
- boost::optional<V1LogBuilder> optLogBuilder;
+ boost::optional<V1LogBuilder> optV1LogBuilder;
+ boost::optional<v2_log_builder::V2LogBuilder> optV2LogBuilder;
UpdateNode::UpdateNodeApplyParams updateNodeApplyParams;
- if (applyParams.logMode != ApplyParams::LogMode::kDoNotGenerateOplogEntry) {
+ if (applyParams.logMode == ApplyParams::LogMode::kGenerateOnlyV1OplogEntry) {
// In versions since 3.6, the absence of a $v field indicates either a
// replacement-style update or a "classic" modifier-style update.
//
@@ -61,8 +63,11 @@ public:
// (b) It is easy to distinguish from $v: 2 delta-style oplog entries.
const bool includeVersionField = true;
- optLogBuilder.emplace(logDocument.root(), includeVersionField);
- updateNodeApplyParams.logBuilder = optLogBuilder.get_ptr();
+ optV1LogBuilder.emplace(logDocument.root(), includeVersionField);
+ updateNodeApplyParams.logBuilder = optV1LogBuilder.get_ptr();
+ } else if (applyParams.logMode == ApplyParams::LogMode::kGenerateOplogEntry) {
+ optV2LogBuilder.emplace();
+ updateNodeApplyParams.logBuilder = optV2LogBuilder.get_ptr();
}
auto ret = _updateTree->apply(applyParams, updateNodeApplyParams);
diff --git a/src/mongo/db/update/v2_log_builder.cpp b/src/mongo/db/update/v2_log_builder.cpp
index 45b49e24a13..aec1148f22f 100644
--- a/src/mongo/db/update/v2_log_builder.cpp
+++ b/src/mongo/db/update/v2_log_builder.cpp
@@ -29,6 +29,8 @@
#include "mongo/db/update/v2_log_builder.h"
+#include <stack>
+
#include "mongo/base/checked_cast.h"
#include "mongo/db/field_ref.h"
#include "mongo/db/update/update_oplog_entry_serialization.h"
@@ -86,7 +88,7 @@ Status V2LogBuilder::logUpdatedField(const RuntimeUpdatePath& path, mutablebson:
Status V2LogBuilder::logCreatedField(const RuntimeUpdatePath& path,
int idxOfFirstNewComponent,
mutablebson::Element elt) {
- auto newNode = std::make_unique<InsertElement>(elt);
+ auto newNode = std::make_unique<InsertNode>(elt);
addNodeAtPath(path, &_root, std::move(newNode), idxOfFirstNewComponent);
return Status::OK();
}
@@ -94,7 +96,7 @@ Status V2LogBuilder::logCreatedField(const RuntimeUpdatePath& path,
Status V2LogBuilder::logCreatedField(const RuntimeUpdatePath& path,
int idxOfFirstNewComponent,
BSONElement elt) {
- auto newNode = std::make_unique<InsertElement>(elt);
+ auto newNode = std::make_unique<InsertNode>(elt);
addNodeAtPath(path, &_root, std::move(newNode), idxOfFirstNewComponent);
return Status::OK();
}
@@ -179,126 +181,245 @@ void appendElementToBuilder(stdx::variant<mutablebson::Element, BSONElement> ele
[&](BSONElement element) { builder->appendAs(element, fieldName); }},
elem);
}
-void serializeNewlyCreatedDocument(DocumentNode* const node, BSONObjBuilder* out) {
- for (auto&& [fieldName, child] : node->inserts) {
- if (child->type() == NodeType::kInsert) {
- appendElementToBuilder(checked_cast<InsertElement*>(child)->elt, fieldName, out);
- continue;
+
+// Construction of the $v:2 diff needs to handle the same number of levels of recursion as the
+// maximum permitted BSON depth. In order to avoid the possibility of stack overflow, which has
+// been observed in configurations that use small stack sizes(such as 'dbg=on'), we use an explicit
+// stack data structure stored on the heap instead.
+//
+// The Frame class represents one "frame" of this explicit stack.
+class Frame {
+public:
+ virtual ~Frame() {}
+
+ // When execute() is called, the Frame may either return a new Frame to be placed on top of the
+ // stack, or return nullptr, indicating that the frame has finished and can be destroyed.
+ //
+ // If a Frame returns a new stack frame, it must be able to pick up where it left off when
+ // execute() is called on it again.
+ virtual std::unique_ptr<Frame> execute() = 0;
+};
+using UniqueFrame = std::unique_ptr<Frame>;
+
+// Helper used for creating a new frame from a sub-diff node. Definition depends on some of the
+// *Frame constructors.
+UniqueFrame makeSubNodeFrameHelper(InternalNode* node, BSONObjBuilder builder);
+// Given a 'node' stored in the 'inserts' section of an InternalNode, will either append that
+// node's value to the given builder, or return a new stack frame which will build the object to be
+// inserted. 'node' must be an InsertionNode or a DocumentInsertNode.
+UniqueFrame handleInsertHelper(StringData fieldName, Node* node, BSONObjBuilder* bob);
+
+// Stack frame used to maintain state while serializing DocumentInsertionNodes.
+class DocumentInsertFrame final : public Frame {
+public:
+ DocumentInsertFrame(const DocumentInsertionNode& node, BSONObjBuilder bob)
+ : _node(node), _bob(std::move(bob)) {}
+
+ UniqueFrame execute() override {
+ for (; _insertIdx < _node.children.size(); ++_insertIdx) {
+ auto&& [fieldName, child] = _node.inserts[_insertIdx];
+
+ if (auto newFrame = handleInsertHelper(fieldName, child, &_bob)) {
+ ++_insertIdx;
+ return newFrame;
+ }
}
- BSONObjBuilder childBuilder(out->subobjStart(fieldName));
- serializeNewlyCreatedDocument(checked_cast<DocumentNode* const>(child), &childBuilder);
+ return nullptr;
}
-}
-// Mutually recursive with writeArrayDiff().
-void writeSubNodeHelper(InternalNode* node, BSONObjBuilder* builder);
-
-void writeArrayDiff(const ArrayNode& node, BSONObjBuilder* builder) {
- builder->append(doc_diff::kArrayHeader, true);
- for (auto&& [idx, child] : node.children) {
- auto idxAsStr = std::to_string(idx);
- switch (child->type()) {
- case (NodeType::kUpdate): {
- const auto& valueNode = checked_cast<const UpdateNode&>(*child);
- appendElementToBuilder(
- valueNode.elt, doc_diff::kUpdateSectionFieldName + idxAsStr, builder);
- break;
- }
- case (NodeType::kInsert): {
- const auto& valueNode = checked_cast<const InsertElement&>(*child);
- appendElementToBuilder(
- valueNode.elt, doc_diff::kUpdateSectionFieldName + idxAsStr, builder);
- break;
+private:
+ size_t _insertIdx = 0;
+ const DocumentInsertionNode& _node;
+ BSONObjBuilder _bob;
+};
+
+// Stack frame used to maintain state while serializing DocumentSubDiffNodes.
+class DocumentSubDiffFrame final : public Frame {
+public:
+ DocumentSubDiffFrame(const DocumentSubDiffNode& node, BSONObjBuilder bob)
+ : _node(node), _bob(std::move(bob)) {}
+
+ UniqueFrame execute() override {
+ if (!_wroteDeletesAndUpdates) {
+ if (!_node.deletes.empty()) {
+ BSONObjBuilder subBob(_bob.subobjStart(doc_diff::kDeleteSectionFieldName));
+ for (auto&& [fieldName, node] : _node.deletes) {
+ // The deletes are logged in the form {fieldName: false} in $v:2 format.
+ subBob.append(fieldName, false);
+ }
}
- case (NodeType::kDocumentInsert): {
- // This represents that the array element is being created which has a sub-object.
- //
- // For example {$set: {"a.0.c": 1}} when the input document is {a: []}. Here we need
- // to create the array element at '0', then sub document 'c'.
- BSONObjBuilder childBuilder =
- builder->subobjStart(doc_diff::kUpdateSectionFieldName + idxAsStr);
- serializeNewlyCreatedDocument(checked_cast<DocumentNode*>(child.get()),
- &childBuilder);
- break;
+ if (!_node.updates.empty()) {
+ BSONObjBuilder subBob(_bob.subobjStart(doc_diff::kUpdateSectionFieldName));
+ for (auto&& [fieldName, node] : _node.updates) {
+ appendElementToBuilder(node->elt, fieldName, &subBob);
+ }
}
- case (NodeType::kDocumentSubDiff):
- case (NodeType::kArray): {
- InternalNode* subNode = checked_cast<InternalNode*>(child.get());
- BSONObjBuilder childBuilder = builder->subobjStart(
- std::string(1, doc_diff::kSubDiffSectionFieldPrefix) + idxAsStr);
- writeSubNodeHelper(subNode, &childBuilder);
- break;
+ _wroteDeletesAndUpdates = true;
+ }
+
+ for (; _insertIdx < _node.inserts.size(); ++_insertIdx) {
+ if (!_insertBob) {
+ _insertBob.emplace(_bob.subobjStart(doc_diff::kInsertSectionFieldName));
}
- case (NodeType::kDelete): {
- MONGO_UNREACHABLE;
+
+ auto&& [fieldName, child] = _node.inserts[_insertIdx];
+
+ if (auto newFrame = handleInsertHelper(fieldName, child, _insertBob.get_ptr())) {
+ ++_insertIdx;
+ return newFrame;
}
}
- }
-}
-void writeDocumentDiff(const DocumentNode& node, BSONObjBuilder* builder) {
- if (!node.deletes.empty()) {
- BSONObjBuilder subBob(builder->subobjStart(doc_diff::kDeleteSectionFieldName));
- for (auto&& [fieldName, node] : node.deletes) {
- // The deletes are logged in the form {fieldName: false} in $v:2 format.
- subBob.append(fieldName, false);
+ if (_insertBob) {
+ // All inserts have been written so we destroy the insert builder now.
+ _insertBob = boost::none;
}
- }
- if (!node.updates.empty()) {
- BSONObjBuilder subBob(builder->subobjStart(doc_diff::kUpdateSectionFieldName));
- for (auto&& [fieldName, node] : node.updates) {
- appendElementToBuilder(node->elt, fieldName, &subBob);
+
+ if (_subDiffIdx != _node.subDiffs.size()) {
+ auto&& [fieldName, child] = _node.subDiffs[_subDiffIdx];
+
+ BSONObjBuilder childBuilder =
+ _bob.subobjStart(std::string(1, doc_diff::kSubDiffSectionFieldPrefix) + fieldName);
+ ++_subDiffIdx;
+ return makeSubNodeFrameHelper(child, std::move(childBuilder));
}
+
+ return nullptr;
+ }
+
+ BSONObjBuilder& bob() {
+ return _bob;
}
- if (!node.inserts.empty()) {
- BSONObjBuilder insertBob(builder->subobjStart(doc_diff::kInsertSectionFieldName));
- for (auto&& [fieldName, child] : node.inserts) {
- if (child->type() == NodeType::kInsert) {
- appendElementToBuilder(
- checked_cast<InsertElement*>(child)->elt, fieldName, &insertBob);
- continue;
+private:
+ const DocumentSubDiffNode& _node;
+ BSONObjBuilder _bob;
+
+ // Indicates whether or not we've written deletes and updates yet. Since deletes and updates
+ // are always leaf nodes, they are always written in the first call to execute().
+ bool _wroteDeletesAndUpdates = false;
+
+ // Keeps track of which insertion or subDiff is being serialized.
+ size_t _insertIdx = 0;
+ size_t _subDiffIdx = 0;
+
+ boost::optional<BSONObjBuilder> _insertBob;
+};
+
+// Stack frame used to maintain state while serializing ArrayNodes.
+class ArrayFrame final : public Frame {
+public:
+ ArrayFrame(const ArrayNode& node, BSONObjBuilder bob)
+ : _node(node), _bob(std::move(bob)), _childIt(node.children.begin()) {}
+
+ UniqueFrame execute() override {
+ invariant(!_node.children.empty());
+ if (_childIt == _node.children.begin()) {
+ _bob.append(doc_diff::kArrayHeader, true);
+ }
+
+ for (; _childIt != _node.children.end(); ++_childIt) {
+
+ auto&& [idx, child] = *_childIt;
+ auto idxAsStr = std::to_string(idx);
+
+ switch (child->type()) {
+ case (NodeType::kUpdate): {
+ const auto& valueNode = checked_cast<const UpdateNode&>(*child);
+ appendElementToBuilder(
+ valueNode.elt, doc_diff::kUpdateSectionFieldName + idxAsStr, &_bob);
+ break;
+ }
+ case (NodeType::kInsert): {
+ const auto& valueNode = checked_cast<const InsertNode&>(*child);
+ appendElementToBuilder(
+ valueNode.elt, doc_diff::kUpdateSectionFieldName + idxAsStr, &_bob);
+ break;
+ }
+ case (NodeType::kDocumentInsert): {
+ // This represents an array element that is being created with a sub object.
+ //
+ // For example {$set: {"a.0.c": 1}} when the input document is {a: []}. Here we
+ // need to create the array element at '0', then sub document 'c'.
+
+ ++_childIt;
+ return std::make_unique<DocumentInsertFrame>(
+ *checked_cast<DocumentInsertionNode*>(child.get()),
+ BSONObjBuilder(
+ _bob.subobjStart(doc_diff::kUpdateSectionFieldName + idxAsStr)));
+ }
+ case (NodeType::kDocumentSubDiff):
+ case (NodeType::kArray): {
+ InternalNode* subNode = checked_cast<InternalNode*>(child.get());
+ BSONObjBuilder childBuilder = _bob.subobjStart(
+ std::string(1, doc_diff::kSubDiffSectionFieldPrefix) + idxAsStr);
+
+ ++_childIt;
+ return makeSubNodeFrameHelper(subNode, std::move(childBuilder));
+ }
+ case (NodeType::kDelete): {
+ MONGO_UNREACHABLE;
+ }
}
- // This represents a new document. While the modifier-style update system
- // was capable of writing paths which would implicitly create new
- // documents, there is no equivalent in $v: 2 updates.
- //
- // For example {$set: {"a.b.c": 1}} would create document 'a' and 'a.b' if
- // necessary.
- //
- // Since $v:2 entries don't have this capability, we instead build the new
- // object and log it as an insert. For example, applying the above $set on
- // document {a: {}} will be logged as an insert of the value {b: {c: 1}} on
- // document 'a'.
- invariant(child->type() == NodeType::kDocumentInsert);
- BSONObjBuilder subBob = insertBob.subobjStart(fieldName);
- serializeNewlyCreatedDocument(checked_cast<DocumentNode*>(child), &subBob);
}
+
+ return nullptr;
}
- for (auto&& [fieldName, child] : node.subDiffs) {
- BSONObjBuilder childBuilder =
- builder->subobjStart(std::string(1, doc_diff::kSubDiffSectionFieldPrefix) + fieldName);
- writeSubNodeHelper(child, &childBuilder);
+private:
+ const ArrayNode& _node;
+ BSONObjBuilder _bob;
+ decltype(ArrayNode::children)::const_iterator _childIt;
+};
+
+BSONObj writeDiff(const DocumentSubDiffNode& root) {
+ std::stack<UniqueFrame> stack;
+ stack.push(std::make_unique<DocumentSubDiffFrame>(root, BSONObjBuilder{}));
+
+ // Iterate until the stack size is one and there is no more work to be done.
+ while (true) {
+ auto nextFrame = stack.top()->execute();
+ if (nextFrame) {
+ stack.push(std::move(nextFrame));
+ } else if (stack.size() == 1) {
+ break;
+ } else {
+ stack.pop();
+ }
}
+
+ invariant(stack.size() == 1);
+
+ auto& topFrame = checked_cast<DocumentSubDiffFrame&>(*stack.top());
+ return topFrame.bob().obj();
}
-void writeSubNodeHelper(InternalNode* node, BSONObjBuilder* builder) {
+UniqueFrame makeSubNodeFrameHelper(InternalNode* node, BSONObjBuilder builder) {
if (node->type() == NodeType::kArray) {
- writeArrayDiff(*checked_cast<ArrayNode*>(node), builder);
+ return std::make_unique<ArrayFrame>(*checked_cast<ArrayNode*>(node), std::move(builder));
} else {
- invariant(node->type() == NodeType::kDocumentSubDiff ||
- node->type() == NodeType::kDocumentInsert);
- writeDocumentDiff(*checked_cast<DocumentNode*>(node), builder);
+ // We never expect to see a DocumentInsertionNode under the 'subDiffs' section of an
+ // internal node.
+ invariant(node->type() == NodeType::kDocumentSubDiff);
+ return std::make_unique<DocumentSubDiffFrame>(*checked_cast<DocumentSubDiffNode*>(node),
+ std::move(builder));
}
}
-} // namespace
+UniqueFrame handleInsertHelper(StringData fieldName, Node* node, BSONObjBuilder* bob) {
+ if (node->type() == NodeType::kInsert) {
+ appendElementToBuilder(checked_cast<InsertNode*>(node)->elt, fieldName, bob);
+ return nullptr;
+ }
+ invariant(node->type() == NodeType::kDocumentInsert);
+ return std::make_unique<DocumentInsertFrame>(*checked_cast<DocumentInsertionNode*>(node),
+ BSONObjBuilder(bob->subobjStart(fieldName)));
+}
+} // namespace
BSONObj V2LogBuilder::serialize() const {
- BSONObjBuilder topBuilder;
- writeDocumentDiff(_root, &topBuilder);
- return update_oplog_entry::makeDeltaOplogEntry(topBuilder.obj());
+ auto diff = writeDiff(_root);
+ return update_oplog_entry::makeDeltaOplogEntry(diff);
}
-} // namespace mongo::v2_log_builder \ No newline at end of file
+} // namespace mongo::v2_log_builder
diff --git a/src/mongo/db/update/v2_log_builder.h b/src/mongo/db/update/v2_log_builder.h
index d0553cb54b3..a26d7b596eb 100644
--- a/src/mongo/db/update/v2_log_builder.h
+++ b/src/mongo/db/update/v2_log_builder.h
@@ -59,9 +59,9 @@ struct Node {
* 'DocumentInsertionNode' also repesent an insert for the cases where an object is created
* implicity.
*/
-struct InsertElement : public Node {
- InsertElement(mutablebson::Element el) : elt(el) {}
- InsertElement(BSONElement el) : elt(el) {}
+struct InsertNode : public Node {
+ InsertNode(mutablebson::Element el) : elt(el) {}
+ InsertNode(BSONElement el) : elt(el) {}
NodeType type() const override {
return NodeType::kInsert;