summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-10-12 18:17:31 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-10-17 09:25:40 -0400
commitd77201bbde61bf9e19eca81d73bbcb8bd85c757c (patch)
tree74d3ab587646f620aadd8c6ad92730a17a32d907
parent5eb95437e55acb07680c72a8a14a2f485bce94d7 (diff)
downloadmongo-d77201bbde61bf9e19eca81d73bbcb8bd85c757c.tar.gz
SERVER-30532 Remove IDL-generated parser for the findAndModify result
Instead only use a generator, but not parser. Also adds lastErrorObject.upserted to the findAndModify retry result.
-rw-r--r--jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js10
-rw-r--r--jstests/sharding/retryable_writes.js9
-rw-r--r--jstests/sharding/write_transactions_during_migration.js10
-rw-r--r--src/mongo/bson/bsonobjbuilder.h5
-rw-r--r--src/mongo/db/SConscript2
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp31
-rw-r--r--src/mongo/db/commands/find_and_modify.idl50
-rw-r--r--src/mongo/db/op_observer_impl.cpp2
-rw-r--r--src/mongo/db/ops/find_and_modify_result.cpp77
-rw-r--r--src/mongo/db/ops/find_and_modify_result.h50
-rw-r--r--src/mongo/db/ops/update_result.cpp12
-rw-r--r--src/mongo/db/ops/update_result.h16
-rw-r--r--src/mongo/db/ops/write_ops_retryability.cpp78
-rw-r--r--src/mongo/db/ops/write_ops_retryability.h12
-rw-r--r--src/mongo/db/ops/write_ops_retryability_test.cpp242
15 files changed, 313 insertions, 293 deletions
diff --git a/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js b/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js
index c06a4cfdc9c..f5af6f88310 100644
--- a/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js
+++ b/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js
@@ -1,20 +1,12 @@
load("jstests/sharding/move_chunk_with_session_helper.js");
(function() {
-
"use strict";
var checkFindAndModifyResult = function(expected, toCheck) {
assert.eq(expected.ok, toCheck.ok);
assert.eq(expected.value, toCheck.value);
-
- // TODO: SERVER-30532: after adding upserted, just compare the entire lastErrorObject
- var expectedLE = expected.lastErrorObject;
- var toCheckLE = toCheck.lastErrorObject;
-
- assert.neq(null, toCheckLE);
- assert.eq(expected.updatedExisting, toCheck.updatedExisting);
- assert.eq(expected.n, toCheck.n);
+ assert.eq(expected.lastErrorObject, toCheck.lastErrorObject);
};
var lsid = UUID();
diff --git a/jstests/sharding/retryable_writes.js b/jstests/sharding/retryable_writes.js
index f83c1b9cdc7..8d6269fb722 100644
--- a/jstests/sharding/retryable_writes.js
+++ b/jstests/sharding/retryable_writes.js
@@ -8,14 +8,7 @@
function checkFindAndModifyResult(expected, toCheck) {
assert.eq(expected.ok, toCheck.ok);
assert.eq(expected.value, toCheck.value);
-
- // TODO: SERVER-30532: after adding upserted, just compare the entire lastErrorObject
- var expectedLE = expected.lastErrorObject;
- var toCheckLE = toCheck.lastErrorObject;
-
- assert.neq(null, toCheckLE);
- assert.eq(expected.updatedExisting, toCheck.updatedExisting);
- assert.eq(expected.n, toCheck.n);
+ assert.docEq(expected.lastErrorObject, toCheck.lastErrorObject);
}
function runTests(mainConn, priConn) {
diff --git a/jstests/sharding/write_transactions_during_migration.js b/jstests/sharding/write_transactions_during_migration.js
index 7c52628e05e..c16ca9845f5 100644
--- a/jstests/sharding/write_transactions_during_migration.js
+++ b/jstests/sharding/write_transactions_during_migration.js
@@ -13,7 +13,6 @@ load('./jstests/libs/chunk_manipulation_util.js');
* 4. Retry writes and confirm that writes are not duplicated.
*/
(function() {
-
"use strict";
var staticMongod = MongoRunner.runMongod({}); // For startParallelOps.
@@ -67,14 +66,7 @@ load('./jstests/libs/chunk_manipulation_util.js');
assert.eq(findAndModifyResult.ok, findAndModifyRetryResult.ok);
assert.eq(findAndModifyResult.value, findAndModifyRetryResult.value);
-
- // TODO: SERVER-30532: after adding upserted, just compare the entire lastErrorObject
- var expectedLE = findAndModifyResult.lastErrorObject;
- var toCheckLE = findAndModifyRetryResult.lastErrorObject;
-
- assert.neq(null, toCheckLE);
- assert.eq(findAndModifyResult.updatedExisting, findAndModifyRetryResult.updatedExisting);
- assert.eq(findAndModifyResult.n, findAndModifyRetryResult.n);
+ assert.eq(findAndModifyResult.lastErrorObject, findAndModifyRetryResult.lastErrorObject);
assert.eq(1, testDB.user.findOne({x: 30}).y);
diff --git a/src/mongo/bson/bsonobjbuilder.h b/src/mongo/bson/bsonobjbuilder.h
index 3b263ca3355..38dae8234fa 100644
--- a/src/mongo/bson/bsonobjbuilder.h
+++ b/src/mongo/bson/bsonobjbuilder.h
@@ -500,11 +500,6 @@ public:
return appendSymbol(fieldName, symbol.symbol);
}
- /** Implements builder interface but no-op in ObjBuilder */
- void appendNull() {
- msgasserted(16234, "Invalid call to appendNull in BSONObj Builder.");
- }
-
/** Append a Null element to the object */
BSONObjBuilder& appendNull(StringData fieldName) {
_b.appendNum((char)jstNULL);
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index 5c358768737..7448f3373da 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -1606,6 +1606,7 @@ env.Library(
target='write_ops',
source=[
'ops/delete.cpp',
+ 'ops/find_and_modify_result.cpp',
'ops/insert.cpp',
'ops/parsed_delete.cpp',
'ops/parsed_update.cpp',
@@ -1617,7 +1618,6 @@ env.Library(
'session_catalog.cpp',
'session_txn_record.cpp',
'transaction_history_iterator.cpp',
- env.Idlc('commands/find_and_modify.idl')[0],
env.Idlc('ops/single_write_result.idl')[0],
env.Idlc('session_txn_record.idl')[0],
],
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index 3d31e47ee06..59c1c387708 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -48,6 +48,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/delete_request.h"
+#include "mongo/db/ops/find_and_modify_result.h"
#include "mongo/db/ops/insert.h"
#include "mongo/db/ops/parsed_delete.h"
#include "mongo/db/ops/parsed_update.h"
@@ -168,25 +169,18 @@ void appendCommandResponse(const PlanExecutor* exec,
bool isRemove,
const boost::optional<BSONObj>& value,
BSONObjBuilder* result) {
- BSONObjBuilder lastErrorObjBuilder(result->subobjStart("lastErrorObject"));
if (isRemove) {
- lastErrorObjBuilder.appendNumber("n", getDeleteStats(exec)->docsDeleted);
+ find_and_modify::serializeRemove(getDeleteStats(exec)->docsDeleted, value, result);
} else {
- const UpdateStats* updateStats = getUpdateStats(exec);
- lastErrorObjBuilder.appendBool("updatedExisting", updateStats->nMatched > 0);
- lastErrorObjBuilder.appendNumber("n", updateStats->inserted ? 1 : updateStats->nMatched);
- // Note we have to use the objInserted from the stats here, rather than 'value'
- // because the _id field could have been excluded by a projection.
- if (!updateStats->objInserted.isEmpty()) {
- lastErrorObjBuilder.appendAs(updateStats->objInserted["_id"], kUpsertedFieldName);
- }
- }
- lastErrorObjBuilder.doneFast();
-
- if (value) {
- result->append("value", *value);
- } else {
- result->appendNull("value");
+ const auto updateStats = getUpdateStats(exec);
+
+ // Note we have to use the objInserted from the stats here, rather than 'value' because the
+ // _id field could have been excluded by a projection.
+ find_and_modify::serializeUpsert(updateStats->inserted ? 1 : updateStats->nMatched,
+ value,
+ updateStats->nMatched > 0,
+ updateStats->objInserted,
+ result);
}
}
@@ -360,8 +354,7 @@ public:
auto session = OperationContextSession::get(opCtx);
if (auto entry =
session->checkStatementExecuted(opCtx, *opCtx->getTxnNumber(), stmtId)) {
- auto findAndModifyResult = parseOplogEntryForFindAndModify(opCtx, args, *entry);
- findAndModifyResult.serialize(&result);
+ parseOplogEntryForFindAndModify(opCtx, args, *entry, &result);
return true;
}
}
diff --git a/src/mongo/db/commands/find_and_modify.idl b/src/mongo/db/commands/find_and_modify.idl
deleted file mode 100644
index 694134c7392..00000000000
--- a/src/mongo/db/commands/find_and_modify.idl
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2017 MongoDB Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License, version 3,
-# as published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-# This IDL file describes the BSON format for a LogicalSessionId, and
-# handles the serialization to and deserialization from its BSON representation
-# for that class.
-
-global:
- cpp_namespace: "mongo"
-
-imports:
- - "mongo/idl/basic_types.idl"
-
-structs:
-
- FindAndModifyLastError:
- description: "Contains execution details for the findAndModify command"
- strict: true
- fields:
- updatedExisting:
- description: "Specifies whether the command modified an existing document"
- type: bool
- optional: true
- n:
- description: "Specifies the number of documents that were inserted/deleted or
- matched the update predicate"
- type: safeInt64
-
- FindAndModifyResult:
- description: "Contains the result from a findAndModify command"
- strict: false
- fields:
- lastErrorObject:
- type: FindAndModifyLastError
- value:
- description: "Contains document before or after the write depending on the 'new'
- field of the request was set to true or false"
- type: object
diff --git a/src/mongo/db/op_observer_impl.cpp b/src/mongo/db/op_observer_impl.cpp
index 79906de7f82..559b44bf72d 100644
--- a/src/mongo/db/op_observer_impl.cpp
+++ b/src/mongo/db/op_observer_impl.cpp
@@ -128,7 +128,7 @@ OpTimeBundle replLogUpdate(OperationContext* opCtx,
BSONObj storeObj;
if (args.storeDocOption == OplogUpdateEntryArgs::StoreDocOption::PreImage) {
invariant(args.preImageDoc);
- storeObj = args.preImageDoc.value();
+ storeObj = *args.preImageDoc;
} else if (args.storeDocOption == OplogUpdateEntryArgs::StoreDocOption::PostImage) {
storeObj = args.updatedDoc;
}
diff --git a/src/mongo/db/ops/find_and_modify_result.cpp b/src/mongo/db/ops/find_and_modify_result.cpp
new file mode 100644
index 00000000000..30f8dad9b6d
--- /dev/null
+++ b/src/mongo/db/ops/find_and_modify_result.cpp
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kWrite
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/ops/find_and_modify_result.h"
+
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/db/lasterror.h"
+
+namespace mongo {
+namespace find_and_modify {
+namespace {
+
+void appendValue(const boost::optional<BSONObj>& value, BSONObjBuilder* builder) {
+ if (value) {
+ builder->append("value", *value);
+ } else {
+ builder->appendNull("value");
+ }
+}
+
+} // namespace
+
+void serializeRemove(size_t n, const boost::optional<BSONObj>& value, BSONObjBuilder* builder) {
+ BSONObjBuilder lastErrorObjBuilder(builder->subobjStart("lastErrorObject"));
+ builder->appendNumber("n", n);
+ lastErrorObjBuilder.doneFast();
+
+ appendValue(value, builder);
+}
+
+void serializeUpsert(size_t n,
+ const boost::optional<BSONObj>& value,
+ bool updatedExisting,
+ const BSONObj& objInserted,
+ BSONObjBuilder* builder) {
+ BSONObjBuilder lastErrorObjBuilder(builder->subobjStart("lastErrorObject"));
+ lastErrorObjBuilder.appendNumber("n", n);
+ lastErrorObjBuilder.appendBool("updatedExisting", updatedExisting);
+ if (!objInserted.isEmpty()) {
+ lastErrorObjBuilder.appendAs(objInserted["_id"], kUpsertedFieldName);
+ }
+ lastErrorObjBuilder.doneFast();
+
+ appendValue(value, builder);
+}
+
+} // namespace find_and_modify
+} // namespace mongo
diff --git a/src/mongo/db/ops/find_and_modify_result.h b/src/mongo/db/ops/find_and_modify_result.h
new file mode 100644
index 00000000000..c335c5022fd
--- /dev/null
+++ b/src/mongo/db/ops/find_and_modify_result.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+
+#include "mongo/bson/bsonobj.h"
+
+namespace mongo {
+
+class BSONObjBuilder;
+
+namespace find_and_modify {
+
+void serializeRemove(size_t n, const boost::optional<BSONObj>& value, BSONObjBuilder* builder);
+
+void serializeUpsert(size_t n,
+ const boost::optional<BSONObj>& value,
+ bool updatedExisting,
+ const BSONObj& objInserted,
+ BSONObjBuilder* builder);
+
+} // namespace find_and_modify
+} // namespace mongo
diff --git a/src/mongo/db/ops/update_result.cpp b/src/mongo/db/ops/update_result.cpp
index 97a5a5332df..93a9e152030 100644
--- a/src/mongo/db/ops/update_result.cpp
+++ b/src/mongo/db/ops/update_result.cpp
@@ -1,7 +1,5 @@
-//@file update_result.cpp
-
/**
- * Copyright (C) 2008-2014 MongoDB Inc.
+ * Copyright (C) 2017 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
@@ -28,6 +26,7 @@
* it in the license file.
*/
+
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kWrite
#include "mongo/platform/basic.h"
@@ -36,6 +35,7 @@
#include "mongo/db/lasterror.h"
#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -55,4 +55,10 @@ UpdateResult::UpdateResult(bool existing_,
LOG(4) << "UpdateResult -- " << redact(toString());
}
+std::string UpdateResult::toString() const {
+ return str::stream() << " upserted: " << upserted << " modifiers: " << modifiers
+ << " existing: " << existing << " numDocsModified: " << numDocsModified
+ << " numMatched: " << numMatched;
+}
+
} // namespace mongo
diff --git a/src/mongo/db/ops/update_result.h b/src/mongo/db/ops/update_result.h
index 2c3107e3ea1..1b0a40520ee 100644
--- a/src/mongo/db/ops/update_result.h
+++ b/src/mongo/db/ops/update_result.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2013 10gen Inc.
+ * Copyright (C) 2017 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
@@ -28,15 +28,10 @@
#pragma once
-#include "mongo/db/curop.h"
-#include "mongo/db/jsobj.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/util/mongoutils/str.h"
+#include "mongo/bson/bsonobj.h"
namespace mongo {
-namespace str = mongoutils::str;
-
struct UpdateResult {
UpdateResult(bool existing_,
bool modifiers_,
@@ -44,6 +39,7 @@ struct UpdateResult {
unsigned long long numMatched_,
const BSONObj& upsertedObject_);
+ std::string toString() const;
// if existing objects were modified
const bool existing;
@@ -59,12 +55,6 @@ struct UpdateResult {
// if something was upserted, the new _id of the object
BSONObj upserted;
-
- const std::string toString() const {
- return str::stream() << " upserted: " << upserted << " modifiers: " << modifiers
- << " existing: " << existing << " numDocsModified: " << numDocsModified
- << " numMatched: " << numMatched;
- }
};
} // namespace mongo
diff --git a/src/mongo/db/ops/write_ops_retryability.cpp b/src/mongo/db/ops/write_ops_retryability.cpp
index 3d4fc90fb7e..28ce5bed8be 100644
--- a/src/mongo/db/ops/write_ops_retryability.cpp
+++ b/src/mongo/db/ops/write_ops_retryability.cpp
@@ -28,18 +28,16 @@
#include "mongo/platform/basic.h"
+#include "mongo/db/ops/write_ops_retryability.h"
+
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/namespace_string.h"
-#include "mongo/db/operation_context.h"
-#include "mongo/db/ops/single_write_result_gen.h"
-#include "mongo/db/ops/write_ops.h"
+#include "mongo/db/ops/find_and_modify_result.h"
#include "mongo/db/ops/write_ops_exec.h"
-#include "mongo/db/ops/write_ops_retryability.h"
#include "mongo/db/query/find_and_modify_request.h"
#include "mongo/logger/redaction.h"
namespace mongo {
-
namespace {
/**
@@ -141,47 +139,26 @@ BSONObj extractPreOrPostImage(OperationContext* opCtx, const repl::OplogEntry& o
* previous execution of the command. In the case of nested oplog entry where the correct links
* are in the top level oplog, oplogWithCorrectLinks can be used to specify the outer oplog.
*/
-FindAndModifyResult parseOplogEntryForFindAndModify(OperationContext* opCtx,
- const FindAndModifyRequest& request,
- const repl::OplogEntry& oplogEntry,
- const repl::OplogEntry& oplogWithCorrectLinks) {
- const auto opType = oplogEntry.getOpType();
-
+void parseOplogEntryForFindAndModify(OperationContext* opCtx,
+ const FindAndModifyRequest& request,
+ const repl::OplogEntry& oplogEntry,
+ const repl::OplogEntry& oplogWithCorrectLinks,
+ BSONObjBuilder* builder) {
validateFindAndModifyRetryability(request, oplogEntry, oplogWithCorrectLinks);
- FindAndModifyResult result;
-
- if (opType == repl::OpTypeEnum::kDelete) {
- FindAndModifyLastError lastError;
- lastError.setN(1);
- result.setLastErrorObject(std::move(lastError));
- result.setValue(extractPreOrPostImage(opCtx, oplogWithCorrectLinks));
-
- return result;
+ switch (oplogEntry.getOpType()) {
+ case repl::OpTypeEnum::kInsert:
+ return find_and_modify::serializeUpsert(
+ 1, oplogEntry.getObject(), false, oplogEntry.getObject(), builder);
+ case repl::OpTypeEnum::kUpdate:
+ return find_and_modify::serializeUpsert(
+ 1, extractPreOrPostImage(opCtx, oplogWithCorrectLinks), true, {}, builder);
+ case repl::OpTypeEnum::kDelete:
+ return find_and_modify::serializeRemove(
+ 1, extractPreOrPostImage(opCtx, oplogWithCorrectLinks), builder);
+ default:
+ MONGO_UNREACHABLE;
}
-
- // Upsert case
- if (opType == repl::OpTypeEnum::kInsert) {
- FindAndModifyLastError lastError;
- lastError.setN(1);
- lastError.setUpdatedExisting(false);
- // TODO: SERVER-30532 set upserted
-
- result.setLastErrorObject(std::move(lastError));
- result.setValue(oplogEntry.getObject().getOwned());
-
- return result;
- }
-
- // Update case
- FindAndModifyLastError lastError;
- lastError.setN(1);
- lastError.setUpdatedExisting(true);
-
- result.setLastErrorObject(std::move(lastError));
- result.setValue(extractPreOrPostImage(opCtx, oplogWithCorrectLinks));
-
- return result;
}
repl::OplogEntry getInnerNestedOplogEntry(const repl::OplogEntry& entry) {
@@ -267,16 +244,17 @@ SingleWriteResult parseOplogEntryForDelete(const repl::OplogEntry& entry) {
return res;
}
-FindAndModifyResult parseOplogEntryForFindAndModify(OperationContext* opCtx,
- const FindAndModifyRequest& request,
- const repl::OplogEntry& oplogEntry) {
+void parseOplogEntryForFindAndModify(OperationContext* opCtx,
+ const FindAndModifyRequest& request,
+ const repl::OplogEntry& oplogEntry,
+ BSONObjBuilder* builder) {
// Migrated op case.
if (oplogEntry.getOpType() == repl::OpTypeEnum::kNoop) {
- return parseOplogEntryForFindAndModify(
- opCtx, request, getInnerNestedOplogEntry(oplogEntry), oplogEntry);
+ parseOplogEntryForFindAndModify(
+ opCtx, request, getInnerNestedOplogEntry(oplogEntry), oplogEntry, builder);
+ } else {
+ parseOplogEntryForFindAndModify(opCtx, request, oplogEntry, oplogEntry, builder);
}
-
- return parseOplogEntryForFindAndModify(opCtx, request, oplogEntry, oplogEntry);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/write_ops_retryability.h b/src/mongo/db/ops/write_ops_retryability.h
index 37f87a0d742..fa73a4d34ed 100644
--- a/src/mongo/db/ops/write_ops_retryability.h
+++ b/src/mongo/db/ops/write_ops_retryability.h
@@ -28,13 +28,13 @@
#pragma once
-#include "mongo/db/commands/find_and_modify_gen.h"
#include "mongo/db/ops/single_write_result_gen.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/repl/oplog_entry.h"
namespace mongo {
+class BSONObjBuilder;
class FindAndModifyRequest;
class OperationContext;
@@ -49,10 +49,12 @@ SingleWriteResult parseOplogEntryForUpdate(const repl::OplogEntry& entry);
SingleWriteResult parseOplogEntryForDelete(const repl::OplogEntry& entry);
/**
- * Returns the result of a findAndModify based on the oplog entries generated by the operation.
+ * Populates the passed-in builder with the result of a findAndModify based on the oplog entries
+ * generated by the operation.
*/
-FindAndModifyResult parseOplogEntryForFindAndModify(OperationContext* opCtx,
- const FindAndModifyRequest& request,
- const repl::OplogEntry& oplogEntry);
+void parseOplogEntryForFindAndModify(OperationContext* opCtx,
+ const FindAndModifyRequest& request,
+ const repl::OplogEntry& oplogEntry,
+ BSONObjBuilder* builder);
} // namespace mongo
diff --git a/src/mongo/db/ops/write_ops_retryability_test.cpp b/src/mongo/db/ops/write_ops_retryability_test.cpp
index 41774472760..4c6268c8c7f 100644
--- a/src/mongo/db/ops/write_ops_retryability_test.cpp
+++ b/src/mongo/db/ops/write_ops_retryability_test.cpp
@@ -29,16 +29,12 @@
#include "mongo/platform/basic.h"
#include "mongo/bson/bsonmisc.h"
-#include "mongo/db/curop.h"
-#include "mongo/db/db_raii.h"
-#include "mongo/db/dbdirectclient.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/ops/write_ops_retryability.h"
#include "mongo/db/query/find_and_modify_request.h"
#include "mongo/db/repl/mock_repl_coord_server_fixture.h"
#include "mongo/db/repl/oplog_entry.h"
-#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/service_context.h"
#include "mongo/db/service_context_d_test_fixture.h"
#include "mongo/unittest/unittest.h"
@@ -46,21 +42,22 @@
namespace mongo {
namespace {
-using WriteOpsRetryability = ServiceContextMongoDTest;
+using unittest::assertGet;
const BSONObj kNestedOplog(BSON("$sessionMigrateInfo" << 1));
+using WriteOpsRetryability = ServiceContextMongoDTest;
+
TEST_F(WriteOpsRetryability, ParseOplogEntryForInsert) {
- auto entry =
+ const auto entry = assertGet(
repl::OplogEntry::parse(BSON("ts" << Timestamp(50, 10) << "t" << 1LL << "h" << 0LL << "op"
<< "i"
<< "ns"
<< "a.b"
<< "o"
- << BSON("_id" << 1 << "x" << 5)));
- ASSERT(entry.isOK());
+ << BSON("_id" << 1 << "x" << 5))));
- auto res = mongo::parseOplogEntryForInsert(entry.getValue());
+ auto res = parseOplogEntryForInsert(entry);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 0);
@@ -80,7 +77,7 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedInsert) {
kNestedOplog,
innerOplog.toBSON());
- auto res = mongo::parseOplogEntryForInsert(insertOplog);
+ auto res = parseOplogEntryForInsert(insertOplog);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 0);
@@ -88,7 +85,7 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedInsert) {
}
TEST_F(WriteOpsRetryability, ParseOplogEntryForUpdate) {
- auto entry =
+ const auto entry = assertGet(
repl::OplogEntry::parse(BSON("ts" << Timestamp(50, 10) << "t" << 1LL << "h" << 0LL << "op"
<< "u"
<< "ns"
@@ -96,10 +93,9 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForUpdate) {
<< "o"
<< BSON("_id" << 1 << "x" << 5)
<< "o2"
- << BSON("_id" << 1)));
- ASSERT(entry.isOK());
+ << BSON("_id" << 1))));
- auto res = mongo::parseOplogEntryForUpdate(entry.getValue());
+ auto res = parseOplogEntryForUpdate(entry);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 1);
@@ -120,7 +116,7 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedUpdate) {
kNestedOplog,
innerOplog.toBSON());
- auto res = mongo::parseOplogEntryForUpdate(updateOplog);
+ auto res = parseOplogEntryForUpdate(updateOplog);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 1);
@@ -128,16 +124,15 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedUpdate) {
}
TEST_F(WriteOpsRetryability, ParseOplogEntryForUpsert) {
- auto entry =
+ const auto entry = assertGet(
repl::OplogEntry::parse(BSON("ts" << Timestamp(50, 10) << "t" << 1LL << "h" << 0LL << "op"
<< "i"
<< "ns"
<< "a.b"
<< "o"
- << BSON("_id" << 1 << "x" << 5)));
- ASSERT(entry.isOK());
+ << BSON("_id" << 1 << "x" << 5))));
- auto res = mongo::parseOplogEntryForUpdate(entry.getValue());
+ auto res = parseOplogEntryForUpdate(entry);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 0);
@@ -157,7 +152,7 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedUpsert) {
kNestedOplog,
innerOplog.toBSON());
- auto res = mongo::parseOplogEntryForUpdate(insertOplog);
+ auto res = parseOplogEntryForUpdate(insertOplog);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 0);
@@ -165,16 +160,15 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedUpsert) {
}
TEST_F(WriteOpsRetryability, ParseOplogEntryForDelete) {
- auto entry =
+ const auto entry = assertGet(
repl::OplogEntry::parse(BSON("ts" << Timestamp(50, 10) << "t" << 1LL << "h" << 0LL << "op"
<< "d"
<< "ns"
<< "a.b"
<< "o"
- << BSON("_id" << 1 << "x" << 5)));
- ASSERT(entry.isOK());
+ << BSON("_id" << 1 << "x" << 5))));
- auto res = mongo::parseOplogEntryForDelete(entry.getValue());
+ auto res = parseOplogEntryForDelete(entry);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 0);
@@ -194,7 +188,7 @@ TEST_F(WriteOpsRetryability, ParseOplogEntryForNestedDelete) {
kNestedOplog,
innerOplog.toBSON());
- auto res = mongo::parseOplogEntryForDelete(deleteOplog);
+ auto res = parseOplogEntryForDelete(deleteOplog);
ASSERT_EQ(res.getN(), 1);
ASSERT_EQ(res.getNModified(), 0);
@@ -231,31 +225,57 @@ TEST_F(WriteOpsRetryability, ShouldFailIfParsingInsertOplogForDelete) {
ASSERT_THROWS(parseOplogEntryForDelete(insertOplog), AssertionException);
}
-using FindAndModifyRetryability = MockReplCoordServerFixture;
-
-NamespaceString kNs("test.user");
+class FindAndModifyRetryability : public MockReplCoordServerFixture {
+public:
+ FindAndModifyRetryability() = default;
+
+protected:
+ /**
+ * Helper function to return a fully-constructed BSONObj instead of having to use
+ * BSONObjBuilder.
+ */
+ static BSONObj constructFindAndModifyRetryResult(OperationContext* opCtx,
+ const FindAndModifyRequest& request,
+ const repl::OplogEntry& oplogEntry) {
+ BSONObjBuilder builder;
+ parseOplogEntryForFindAndModify(opCtx, request, oplogEntry, &builder);
+ return builder.obj();
+ }
+};
+
+const NamespaceString kNs("test.user");
TEST_F(FindAndModifyRetryability, BasicUpsert) {
auto request = FindAndModifyRequest::makeUpdate(kNs, BSONObj(), BSONObj());
request.setUpsert(true);
- repl::OplogEntry insertOplog(repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("x" << 1));
-
- auto result = parseOplogEntryForFindAndModify(nullptr, request, insertOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_TRUE(lastError.getUpdatedExisting());
- ASSERT_FALSE(lastError.getUpdatedExisting().value());
-
- ASSERT_BSONOBJ_EQ(BSON("x" << 1), result.getValue());
+ repl::OplogEntry insertOplog(repl::OpTime(),
+ 0,
+ repl::OpTypeEnum::kInsert,
+ kNs,
+ BSON("_id"
+ << "ID value"
+ << "x"
+ << 1));
+
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, insertOplog);
+ ASSERT_BSONOBJ_EQ(BSON("lastErrorObject"
+ << BSON("n" << 1 << "updatedExisting" << false << "upserted"
+ << "ID value")
+ << "value"
+ << BSON("_id"
+ << "ID value"
+ << "x"
+ << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, NestedUpsert) {
auto request = FindAndModifyRequest::makeUpdate(kNs, BSONObj(), BSONObj());
request.setUpsert(true);
- repl::OplogEntry innerOplog(repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("x" << 1));
+ repl::OplogEntry innerOplog(
+ repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("_id" << 1));
repl::OplogEntry insertOplog(repl::OpTime(Timestamp(60, 10), 1),
0,
repl::OpTypeEnum::kNoop,
@@ -263,23 +283,22 @@ TEST_F(FindAndModifyRetryability, NestedUpsert) {
kNestedOplog,
innerOplog.toBSON());
- auto result = parseOplogEntryForFindAndModify(nullptr, request, insertOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_TRUE(lastError.getUpdatedExisting());
- ASSERT_FALSE(lastError.getUpdatedExisting().value());
-
- ASSERT_BSONOBJ_EQ(BSON("x" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, insertOplog);
+ ASSERT_BSONOBJ_EQ(BSON("lastErrorObject"
+ << BSON("n" << 1 << "updatedExisting" << false << "upserted" << 1)
+ << "value"
+ << BSON("_id" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, AttemptingToRetryUpsertWithUpdateWithoutUpsertErrors) {
auto request = FindAndModifyRequest::makeUpdate(kNs, BSONObj(), BSONObj());
request.setUpsert(false);
- repl::OplogEntry insertOplog(repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("x" << 1));
+ repl::OplogEntry insertOplog(
+ repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("_id" << 1));
- ASSERT_THROWS(parseOplogEntryForFindAndModify(opCtx(), request, insertOplog),
+ ASSERT_THROWS(constructFindAndModifyRetryResult(opCtx(), request, insertOplog),
AssertionException);
}
@@ -289,7 +308,7 @@ TEST_F(FindAndModifyRetryability, ErrorIfRequestIsPostImageButOplogHasPre) {
repl::OpTime imageOpTime(Timestamp(120, 3), 1);
repl::OplogEntry noteOplog(
- imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("x" << 1 << "z" << 1));
+ imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("_id" << 1 << "z" << 1));
insertOplogEntry(noteOplog);
@@ -297,11 +316,11 @@ TEST_F(FindAndModifyRetryability, ErrorIfRequestIsPostImageButOplogHasPre) {
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
updateOplog.setPreImageOpTime(imageOpTime);
- ASSERT_THROWS(parseOplogEntryForFindAndModify(opCtx(), request, updateOplog),
+ ASSERT_THROWS(constructFindAndModifyRetryResult(opCtx(), request, updateOplog),
AssertionException);
}
@@ -311,14 +330,14 @@ TEST_F(FindAndModifyRetryability, ErrorIfRequestIsUpdateButOplogIsDelete) {
repl::OpTime imageOpTime(Timestamp(120, 3), 1);
repl::OplogEntry noteOplog(
- imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("x" << 1 << "z" << 1));
+ imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("_id" << 1 << "z" << 1));
insertOplogEntry(noteOplog);
repl::OplogEntry oplog(repl::OpTime(), 0, repl::OpTypeEnum::kDelete, kNs, BSON("_id" << 1));
oplog.setPreImageOpTime(imageOpTime);
- ASSERT_THROWS(parseOplogEntryForFindAndModify(opCtx(), request, oplog), AssertionException);
+ ASSERT_THROWS(constructFindAndModifyRetryResult(opCtx(), request, oplog), AssertionException);
}
TEST_F(FindAndModifyRetryability, ErrorIfRequestIsPreImageButOplogHasPost) {
@@ -327,7 +346,7 @@ TEST_F(FindAndModifyRetryability, ErrorIfRequestIsPreImageButOplogHasPost) {
repl::OpTime imageOpTime(Timestamp(120, 3), 1);
repl::OplogEntry noteOplog(
- imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("x" << 1 << "z" << 1));
+ imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("_id" << 1 << "z" << 1));
insertOplogEntry(noteOplog);
@@ -335,11 +354,11 @@ TEST_F(FindAndModifyRetryability, ErrorIfRequestIsPreImageButOplogHasPost) {
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
updateOplog.setPostImageOpTime(imageOpTime);
- ASSERT_THROWS(parseOplogEntryForFindAndModify(opCtx(), request, updateOplog),
+ ASSERT_THROWS(constructFindAndModifyRetryResult(opCtx(), request, updateOplog),
AssertionException);
}
@@ -349,7 +368,7 @@ TEST_F(FindAndModifyRetryability, UpdateWithPreImage) {
repl::OpTime imageOpTime(Timestamp(120, 3), 1);
repl::OplogEntry noteOplog(
- imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("x" << 1 << "z" << 1));
+ imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("_id" << 1 << "z" << 1));
insertOplogEntry(noteOplog);
@@ -357,18 +376,15 @@ TEST_F(FindAndModifyRetryability, UpdateWithPreImage) {
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
updateOplog.setPreImageOpTime(imageOpTime);
- auto result = parseOplogEntryForFindAndModify(opCtx(), request, updateOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_TRUE(lastError.getUpdatedExisting());
- ASSERT_TRUE(lastError.getUpdatedExisting().value());
-
- ASSERT_BSONOBJ_EQ(BSON("x" << 1 << "z" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, updateOplog);
+ ASSERT_BSONOBJ_EQ(BSON("lastErrorObject" << BSON("n" << 1 << "updatedExisting" << true)
+ << "value"
+ << BSON("_id" << 1 << "z" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, NestedUpdateWithPreImage) {
@@ -377,7 +393,7 @@ TEST_F(FindAndModifyRetryability, NestedUpdateWithPreImage) {
repl::OpTime imageOpTime(Timestamp(120, 3), 1);
repl::OplogEntry noteOplog(
- imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("x" << 1 << "z" << 1));
+ imageOpTime, 0, repl::OpTypeEnum::kNoop, kNs, BSON("_id" << 1 << "z" << 1));
insertOplogEntry(noteOplog);
@@ -385,8 +401,8 @@ TEST_F(FindAndModifyRetryability, NestedUpdateWithPreImage) {
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
repl::OplogEntry updateOplog(repl::OpTime(Timestamp(60, 10), 1),
0,
@@ -396,14 +412,11 @@ TEST_F(FindAndModifyRetryability, NestedUpdateWithPreImage) {
innerOplog.toBSON());
updateOplog.setPreImageOpTime(imageOpTime);
- auto result = parseOplogEntryForFindAndModify(opCtx(), request, updateOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_TRUE(lastError.getUpdatedExisting());
- ASSERT_TRUE(lastError.getUpdatedExisting().value());
-
- ASSERT_BSONOBJ_EQ(BSON("x" << 1 << "z" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, updateOplog);
+ ASSERT_BSONOBJ_EQ(BSON("lastErrorObject" << BSON("n" << 1 << "updatedExisting" << true)
+ << "value"
+ << BSON("_id" << 1 << "z" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, UpdateWithPostImage) {
@@ -420,18 +433,15 @@ TEST_F(FindAndModifyRetryability, UpdateWithPostImage) {
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
updateOplog.setPostImageOpTime(imageOpTime);
- auto result = parseOplogEntryForFindAndModify(opCtx(), request, updateOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_TRUE(lastError.getUpdatedExisting());
- ASSERT_TRUE(lastError.getUpdatedExisting().value());
-
- ASSERT_BSONOBJ_EQ(BSON("a" << 1 << "b" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, updateOplog);
+ ASSERT_BSONOBJ_EQ(BSON("lastErrorObject" << BSON("n" << 1 << "updatedExisting" << true)
+ << "value"
+ << BSON("a" << 1 << "b" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, NestedUpdateWithPostImage) {
@@ -448,8 +458,8 @@ TEST_F(FindAndModifyRetryability, NestedUpdateWithPostImage) {
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
repl::OplogEntry updateOplog(repl::OpTime(Timestamp(60, 10), 1),
0,
@@ -459,14 +469,11 @@ TEST_F(FindAndModifyRetryability, NestedUpdateWithPostImage) {
innerOplog.toBSON());
updateOplog.setPostImageOpTime(imageOpTime);
- auto result = parseOplogEntryForFindAndModify(opCtx(), request, updateOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_TRUE(lastError.getUpdatedExisting());
- ASSERT_TRUE(lastError.getUpdatedExisting().value());
-
- ASSERT_BSONOBJ_EQ(BSON("a" << 1 << "b" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, updateOplog);
+ ASSERT_BSONOBJ_EQ(BSON("lastErrorObject" << BSON("n" << 1 << "updatedExisting" << true)
+ << "value"
+ << BSON("a" << 1 << "b" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, UpdateWithPostImageButOplogDoesNotExistShouldError) {
@@ -478,11 +485,11 @@ TEST_F(FindAndModifyRetryability, UpdateWithPostImageButOplogDoesNotExistShouldE
0,
repl::OpTypeEnum::kUpdate,
kNs,
- BSON("x" << 1 << "y" << 1),
- BSON("x" << 1));
+ BSON("_id" << 1 << "y" << 1),
+ BSON("_id" << 1));
updateOplog.setPostImageOpTime(imageOpTime);
- ASSERT_THROWS(parseOplogEntryForFindAndModify(opCtx(), request, updateOplog),
+ ASSERT_THROWS(constructFindAndModifyRetryResult(opCtx(), request, updateOplog),
AssertionException);
}
@@ -499,13 +506,10 @@ TEST_F(FindAndModifyRetryability, BasicRemove) {
repl::OpTime(), 0, repl::OpTypeEnum::kDelete, kNs, BSON("_id" << 20));
removeOplog.setPreImageOpTime(imageOpTime);
- auto result = parseOplogEntryForFindAndModify(opCtx(), request, removeOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_FALSE(lastError.getUpdatedExisting());
-
- ASSERT_BSONOBJ_EQ(BSON("_id" << 20 << "a" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, removeOplog);
+ ASSERT_BSONOBJ_EQ(
+ BSON("lastErrorObject" << BSON("n" << 1) << "value" << BSON("_id" << 20 << "a" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, NestedRemove) {
@@ -528,21 +532,19 @@ TEST_F(FindAndModifyRetryability, NestedRemove) {
innerOplog.toBSON());
removeOplog.setPreImageOpTime(imageOpTime);
- auto result = parseOplogEntryForFindAndModify(opCtx(), request, removeOplog);
-
- auto lastError = result.getLastErrorObject();
- ASSERT_EQ(1, lastError.getN());
- ASSERT_FALSE(lastError.getUpdatedExisting());
-
- ASSERT_BSONOBJ_EQ(BSON("_id" << 20 << "a" << 1), result.getValue());
+ auto result = constructFindAndModifyRetryResult(opCtx(), request, removeOplog);
+ ASSERT_BSONOBJ_EQ(
+ BSON("lastErrorObject" << BSON("n" << 1) << "value" << BSON("_id" << 20 << "a" << 1)),
+ result);
}
TEST_F(FindAndModifyRetryability, AttemptingToRetryUpsertWithRemoveErrors) {
auto request = FindAndModifyRequest::makeRemove(kNs, BSONObj());
- repl::OplogEntry insertOplog(repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("x" << 1));
+ repl::OplogEntry insertOplog(
+ repl::OpTime(), 0, repl::OpTypeEnum::kInsert, kNs, BSON("_id" << 1));
- ASSERT_THROWS(parseOplogEntryForFindAndModify(opCtx(), request, insertOplog),
+ ASSERT_THROWS(constructFindAndModifyRetryResult(opCtx(), request, insertOplog),
AssertionException);
}