/** * Write oplog entry(ies) for the update operation. */ OpTimeBundle replLogUpdate(OperationContext* opCtx, Session* session, const OplogUpdateEntryArgs& args) { BSONObj storeObj; if (args.storeDocOption == OplogUpdateEntryArgs::StoreDocOption::PreImage) { invariant(args.preImageDoc); storeObj = *args.preImageDoc; } else if (args.storeDocOption == OplogUpdateEntryArgs::StoreDocOption::PostImage) { storeObj = args.updatedDoc; } OperationSessionInfo sessionInfo; repl::OplogLink oplogLink; if (session) { sessionInfo.setSessionId(*opCtx->getLogicalSessionId()); sessionInfo.setTxnNumber(*opCtx->getTxnNumber()); oplogLink.prevOpTime = session->getLastWriteOpTime(*opCtx->getTxnNumber()); } OpTimeBundle opTimes; opTimes.wallClockTime = getWallClockTimeForOpLog(opCtx); if (!storeObj.isEmpty() && opCtx->getTxnNumber()) { auto noteUpdateOpTime = logOperation(opCtx, "n", args.nss, args.uuid, storeObj, nullptr, false, opTimes.wallClockTime, sessionInfo, args.stmtId, {}); opTimes.prePostImageOpTime = noteUpdateOpTime; if (args.storeDocOption == OplogUpdateEntryArgs::StoreDocOption::PreImage) { oplogLink.preImageOpTime = noteUpdateOpTime; } else if (args.storeDocOption == OplogUpdateEntryArgs::StoreDocOption::PostImage) { oplogLink.postImageOpTime = noteUpdateOpTime; } } opTimes.writeOpTime = logOperation(opCtx, "u", args.nss, args.uuid, args.update, &args.criteria, args.fromMigrate, opTimes.wallClockTime, sessionInfo, args.stmtId, oplogLink); return opTimes; }
/** * Write oplog entry(ies) for the delete operation. */ OpTimeBundle replLogDelete(OperationContext* opCtx, const NamespaceString& nss, OptionalCollectionUUID uuid, StmtId stmtId, bool fromMigrate, const boost::optional<BSONObj>& deletedDoc) { OperationSessionInfo sessionInfo; repl::OplogLink oplogLink; const auto txnParticipant = TransactionParticipant::get(opCtx); if (txnParticipant) { sessionInfo.setSessionId(*opCtx->getLogicalSessionId()); sessionInfo.setTxnNumber(*opCtx->getTxnNumber()); oplogLink.prevOpTime = txnParticipant->getLastWriteOpTime(*opCtx->getTxnNumber()); } OpTimeBundle opTimes; opTimes.wallClockTime = getWallClockTimeForOpLog(opCtx); if (deletedDoc && opCtx->getTxnNumber()) { auto noteOplog = logOperation(opCtx, "n", nss, uuid, deletedDoc.get(), nullptr, false, opTimes.wallClockTime, sessionInfo, stmtId, {}, false /* prepare */, OplogSlot()); opTimes.prePostImageOpTime = noteOplog; oplogLink.preImageOpTime = noteOplog; } auto& documentKey = documentKeyDecoration(opCtx); opTimes.writeOpTime = logOperation(opCtx, "d", nss, uuid, documentKey, nullptr, fromMigrate, opTimes.wallClockTime, sessionInfo, stmtId, oplogLink, false /* prepare */, OplogSlot()); return opTimes; }
/** * Write oplog entry(ies) for the delete operation. */ OpTimeBundle replLogDelete(OperationContext* opCtx, const NamespaceString& nss, OptionalCollectionUUID uuid, Session* session, StmtId stmtId, bool fromMigrate, const boost::optional<BSONObj>& deletedDoc) { OperationSessionInfo sessionInfo; repl::OplogLink oplogLink; if (session) { sessionInfo.setSessionId(*opCtx->getLogicalSessionId()); sessionInfo.setTxnNumber(*opCtx->getTxnNumber()); oplogLink.prevOpTime = session->getLastWriteOpTime(*opCtx->getTxnNumber()); } OpTimeBundle opTimes; opTimes.wallClockTime = getWallClockTimeForOpLog(opCtx); if (deletedDoc && opCtx->getTxnNumber()) { auto noteOplog = logOperation(opCtx, "n", nss, uuid, deletedDoc.get(), nullptr, false, opTimes.wallClockTime, sessionInfo, stmtId, {}); opTimes.prePostImageOpTime = noteOplog; oplogLink.preImageOpTime = noteOplog; } auto& deleteState = getDeleteState(opCtx); opTimes.writeOpTime = logOperation(opCtx, "d", nss, uuid, deleteState.documentKey, nullptr, fromMigrate, opTimes.wallClockTime, sessionInfo, stmtId, oplogLink); return opTimes; }
/** * Write oplog entry for applyOps/atomic transaction operations. */ OpTimeBundle replLogApplyOps(OperationContext* opCtx, const NamespaceString& cmdNss, const BSONObj& applyOpCmd, const OperationSessionInfo& sessionInfo, StmtId stmtId, const repl::OplogLink& oplogLink, bool prepare, const OplogSlot& oplogSlot) { OpTimeBundle times; times.wallClockTime = getWallClockTimeForOpLog(opCtx); times.writeOpTime = logOperation(opCtx, "c", cmdNss, {}, applyOpCmd, nullptr, false, times.wallClockTime, sessionInfo, stmtId, oplogLink, prepare, oplogSlot); return times; }
static int invokeMonitorCallback (OperationEntry *operation) { MonitorExtension *extension = operation->extension; AsyncMonitorCallback *callback = extension->callback; logOperation(operation, callback); if (callback) { const AsyncMonitorCallbackParameters parameters = { .error = operation->error, .data = operation->data }; if (callback(¶meters)) return 1; } return 0; } static int invokeInputCallback (OperationEntry *operation) { TransferExtension *extension = operation->extension; AsyncInputCallback *callback = extension->direction.input.callback; size_t count; logOperation(operation, callback); if (!callback) return 0; { const AsyncInputCallbackParameters parameters = { .data = operation->data, .buffer = extension->buffer, .size = extension->size, .length = extension->length, .error = operation->error, .end = extension->direction.input.end }; count = callback(¶meters); } if (operation->error) return 0; if (extension->direction.input.end) return 0; operation->finished = 0; if (count) { memmove(extension->buffer, &extension->buffer[count], extension->length -= count); if (extension->length > 0) operation->finished = 1; } return 1; } static int invokeOutputCallback (OperationEntry *operation) { TransferExtension *extension = operation->extension; AsyncOutputCallback *callback = extension->direction.output.callback; logOperation(operation, callback); if (!operation->error && (extension->length < extension->size)) { operation->finished = 0; return 1; } if (callback) { const AsyncOutputCallbackParameters parameters = { .data = operation->data, .buffer = extension->buffer, .size = extension->size, .error = operation->error }; callback(¶meters); } return 0; } static Element * getActiveOperationElement (const FunctionEntry *function) { Queue *queue = function->operations; if (function->methods->invokeCallback == invokeMonitorCallback) return getStackHead(queue); return getQueueHead(queue); }