summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2017-11-01 19:08:53 -0400
committerBenety Goh <benety@mongodb.com>2017-11-06 15:13:37 -0500
commit929570fc836a5940781b6809aa79ab9d6a1a1536 (patch)
treebca28d84c5214932ca1650b23be32670261395bd /src/mongo
parentdc04d7d6f22e6542f9f20cf33cd40015cefcf530 (diff)
downloadmongo-929570fc836a5940781b6809aa79ab9d6a1a1536.tar.gz
SERVER-31300 applyOps() adds missing UUID to individual operations in the oplog entry
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/repl/apply_ops.cpp43
-rw-r--r--src/mongo/db/repl/apply_ops_test.cpp6
2 files changed, 38 insertions, 11 deletions
diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp
index feecb535180..633deed78dc 100644
--- a/src/mongo/db/repl/apply_ops.cpp
+++ b/src/mongo/db/repl/apply_ops.cpp
@@ -104,9 +104,9 @@ Status _applyOps(OperationContext* opCtx,
const std::string& dbName,
const BSONObj& applyOpCmd,
BSONObjBuilder* result,
- int* numApplied) {
+ int* numApplied,
+ BSONArrayBuilder* opsBuilder) {
BSONObj ops = applyOpCmd.firstElement().Obj();
-
// apply
*numApplied = 0;
int errors = 0;
@@ -200,6 +200,22 @@ Status _applyOps(OperationContext* opCtx,
opCtx, ctx.db(), opObj, alwaysUpsert, oplogApplicationMode);
if (!status.isOK())
return status;
+
+ // Append completed op, including UUID if available, to 'opsBuilder'.
+ if (opsBuilder) {
+ if (opObj.hasField("ui") || nss.isSystemDotIndexes() ||
+ !(collection && collection->uuid())) {
+ // No changes needed to operation document.
+ opsBuilder->append(opObj);
+ } else {
+ // Operation document has no "ui" field and collection has a UUID.
+ auto uuid = collection->uuid();
+ BSONObjBuilder opBuilder;
+ opBuilder.appendElements(opObj);
+ uuid->appendToBuilder(&opBuilder, "ui");
+ opsBuilder->append(opBuilder.obj());
+ }
+ }
} else {
try {
status = writeConflictRetry(
@@ -399,8 +415,9 @@ Status applyOps(OperationContext* opCtx,
globalWriteLock.emplace(opCtx);
}
- bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(opCtx, dbName);
+ auto replCoord = repl::ReplicationCoordinator::get(opCtx);
+ bool userInitiatedWritesAndNotPrimary =
+ opCtx->writesAreReplicated() && !replCoord->canAcceptWritesForDatabase(opCtx, dbName);
if (userInitiatedWritesAndNotPrimary)
return Status(ErrorCodes::NotMaster,
@@ -416,7 +433,7 @@ Status applyOps(OperationContext* opCtx,
int numApplied = 0;
if (!isAtomic)
- return _applyOps(opCtx, dbName, applyOpCmd, result, &numApplied);
+ return _applyOps(opCtx, dbName, applyOpCmd, result, &numApplied, nullptr);
// Perform write ops atomically
invariant(globalWriteLock);
@@ -424,13 +441,18 @@ Status applyOps(OperationContext* opCtx,
try {
writeConflictRetry(opCtx, "applyOps", dbName, [&] {
BSONObjBuilder intermediateResult;
+ std::unique_ptr<BSONArrayBuilder> opsBuilder;
+ if (opCtx->writesAreReplicated() &&
+ repl::ReplicationCoordinator::modeMasterSlave != replCoord->getReplicationMode()) {
+ opsBuilder = stdx::make_unique<BSONArrayBuilder>();
+ }
WriteUnitOfWork wunit(opCtx);
numApplied = 0;
{
// Suppress replication for atomic operations until end of applyOps.
repl::UnreplicatedWritesBlock uwb(opCtx);
- uassertStatusOK(
- _applyOps(opCtx, dbName, applyOpCmd, &intermediateResult, &numApplied));
+ uassertStatusOK(_applyOps(
+ opCtx, dbName, applyOpCmd, &intermediateResult, &numApplied, opsBuilder.get()));
}
// Generate oplog entry for all atomic ops collectively.
if (opCtx->writesAreReplicated()) {
@@ -439,8 +461,13 @@ Status applyOps(OperationContext* opCtx,
BSONObjBuilder cmdBuilder;
+ auto opsFieldName = applyOpCmd.firstElement().fieldNameStringData();
for (auto elem : applyOpCmd) {
auto name = elem.fieldNameStringData();
+ if (name == opsFieldName && opsBuilder) {
+ cmdBuilder.append(opsFieldName, opsBuilder->arr());
+ continue;
+ }
if (name == kPreconditionFieldName)
continue;
if (name == bypassDocumentValidationCommandOption())
@@ -460,7 +487,7 @@ Status applyOps(OperationContext* opCtx,
} catch (const DBException& ex) {
if (ex.code() == ErrorCodes::AtomicityFailure) {
// Retry in non-atomic mode.
- return _applyOps(opCtx, dbName, applyOpCmd, result, &numApplied);
+ return _applyOps(opCtx, dbName, applyOpCmd, result, &numApplied, nullptr);
}
BSONArrayBuilder ab;
++numApplied;
diff --git a/src/mongo/db/repl/apply_ops_test.cpp b/src/mongo/db/repl/apply_ops_test.cpp
index c7e14bf6cfc..1f1984245b2 100644
--- a/src/mongo/db/repl/apply_ops_test.cpp
+++ b/src/mongo/db/repl/apply_ops_test.cpp
@@ -242,9 +242,9 @@ TEST_F(ApplyOpsTest, AtomicApplyOpsInsertWithoutUuidIntoCollectionWithUuid) {
BSONObjBuilder resultBuilder;
ASSERT_OK(applyOps(opCtx.get(), "test", cmdObj, &resultBuilder));
- // TODO (SERVER-31300): Insert operation provided by caller did not contain collection uuid but
- // applyOps() should add the uuid to the oplog entry.
- auto expectedCmdObj = cmdObj;
+ // Insert operation provided by caller did not contain collection uuid but applyOps() should add
+ // the uuid to the oplog entry.
+ auto expectedCmdObj = makeApplyOpsWithInsertOperation(nss, uuid, documentToInsert);
ASSERT_BSONOBJ_EQ(expectedCmdObj, _opObserver->onApplyOpsCmdObj);
}