diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-18 17:02:53 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-18 17:02:53 -0300 |
| commit | 959575a5ca598bf5f37fb5cebe7ed1d80d3d71f7 (patch) | |
| tree | acc8d60aedb12b70048e676e8a7349deb0010db8 /src/mongo/db/ops | |
| parent | 76588293975fc059cf076779e4283e6ffaf8afff (diff) | |
New upstream version 6.0.20upstream
Diffstat (limited to 'src/mongo/db/ops')
| -rw-r--r-- | src/mongo/db/ops/SConscript | 2 | ||||
| -rw-r--r-- | src/mongo/db/ops/insert.cpp | 7 | ||||
| -rw-r--r-- | src/mongo/db/ops/insert.h | 1 | ||||
| -rw-r--r-- | src/mongo/db/ops/parsed_update.cpp | 1 | ||||
| -rw-r--r-- | src/mongo/db/ops/update_request.h | 10 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops.cpp | 6 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops.idl | 12 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops_exec.cpp | 57 |
8 files changed, 50 insertions, 46 deletions
diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript index 3e89ae63e36..9ac3c43f9fd 100644 --- a/src/mongo/db/ops/SConscript +++ b/src/mongo/db/ops/SConscript @@ -15,9 +15,9 @@ env.Library( '$BUILD_DIR/mongo/db/catalog/collection_options', '$BUILD_DIR/mongo/db/catalog_raii', '$BUILD_DIR/mongo/db/concurrency/exception_util', - '$BUILD_DIR/mongo/db/curop', '$BUILD_DIR/mongo/db/curop_metrics', '$BUILD_DIR/mongo/db/dbhelpers', + '$BUILD_DIR/mongo/db/query/query_stats/query_stats', '$BUILD_DIR/mongo/db/record_id_helpers', '$BUILD_DIR/mongo/db/repl/oplog', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp index 61d92fda6bf..8c949b333c7 100644 --- a/src/mongo/db/ops/insert.cpp +++ b/src/mongo/db/ops/insert.cpp @@ -87,6 +87,7 @@ Status validateDepth(const BSONObj& obj) { StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, const BSONObj& doc, + bool bypassEmptyTsReplacement, bool* containsDotsAndDollarsField) { bool validationDisabled = DocumentValidationSettings::get(opCtx).isInternalValidationDisabled(); @@ -139,7 +140,8 @@ StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, } if (!validationDisabled) { - if (e.type() == bsonTimestamp && e.timestampValue() == 0) { + if (!bypassEmptyTsReplacement && e.type() == bsonTimestamp && + e.timestampValue() == 0) { // we replace Timestamp(0,0) at the top level with a correct value // in the fast pass, we just mark that we want to swap hasTimestampToFix = true; @@ -187,7 +189,8 @@ StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, BSONElement e = i.next(); if (hadId && e.fieldNameStringData() == "_id") { // no-op - } else if (e.type() == bsonTimestamp && e.timestampValue() == 0) { + } else if (!bypassEmptyTsReplacement && e.type() == bsonTimestamp && + e.timestampValue() == 0) { auto nextTime = VectorClockMutable::get(opCtx)->tickClusterTime(1); b.append(e.fieldName(), nextTime.asTimestamp()); } else { diff --git a/src/mongo/db/ops/insert.h b/src/mongo/db/ops/insert.h index faed6de5890..a523e499d02 100644 --- a/src/mongo/db/ops/insert.h +++ b/src/mongo/db/ops/insert.h @@ -47,6 +47,7 @@ class OperationContext; */ StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, const BSONObj& doc, + bool bypassEmptyTsReplacement = false, bool* containsDotsOrDollarsField = nullptr); /** diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index b9557e4b2fe..a2badffa2aa 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -188,6 +188,7 @@ void ParsedUpdate::parseUpdate() { _driver.setCollator(_expCtx->getCollator()); _driver.setLogOp(true); _driver.setFromOplogApplication(_request->isFromOplogApplication()); + _driver.setBypassEmptyTsReplacement(static_cast<bool>(_request->getBypassEmptyTsReplacement())); // Time-series operations will not result in any documents with dots or dollars fields. if (auto source = _request->source(); source == OperationSource::kTimeseriesInsert || source == OperationSource::kTimeseriesUpdate) { diff --git a/src/mongo/db/ops/update_request.h b/src/mongo/db/ops/update_request.h index 3db331defa9..2a086d8a4ab 100644 --- a/src/mongo/db/ops/update_request.h +++ b/src/mongo/db/ops/update_request.h @@ -209,6 +209,14 @@ public: return _fromOplogApplication; } + void setBypassEmptyTsReplacement(OptionalBool bypassEmptyTsReplacement) { + _bypassEmptyTsReplacement = bypassEmptyTsReplacement; + } + + OptionalBool getBypassEmptyTsReplacement() const { + return _bypassEmptyTsReplacement; + } + void setExplain(boost::optional<ExplainOptions::Verbosity> verbosity) { _explain = verbosity; } @@ -314,6 +322,8 @@ private: // The statement ids of this request. std::vector<StmtId> _stmtIds = {kUninitializedStmtId}; + OptionalBool _bypassEmptyTsReplacement; + // Flags controlling the update. // God bypasses _id checking and index generation. It is only used on behalf of system diff --git a/src/mongo/db/ops/write_ops.cpp b/src/mongo/db/ops/write_ops.cpp index de7df85e564..14cf48fca37 100644 --- a/src/mongo/db/ops/write_ops.cpp +++ b/src/mongo/db/ops/write_ops.cpp @@ -131,6 +131,12 @@ int getWriteCommandRequestBaseSize(const WriteCommandRequestBase& base) { encryptionInfo->toBSON().objsize() + kPerElementOverhead; } + if (auto bypassEmptyTsReplacement = base.getBypassEmptyTsReplacement(); + bypassEmptyTsReplacement.has_value()) { + estSize += write_ops::WriteCommandRequestBase::kBypassEmptyTsReplacementFieldName.size() + + kBoolSize + kPerElementOverhead; + } + return estSize; } diff --git a/src/mongo/db/ops/write_ops.idl b/src/mongo/db/ops/write_ops.idl index ca606f3cfad..e41af05e808 100644 --- a/src/mongo/db/ops/write_ops.idl +++ b/src/mongo/db/ops/write_ops.idl @@ -205,6 +205,12 @@ structs: type: EncryptionInformation optional: true unstable: true + bypassEmptyTsReplacement: + description: "Only applicable for inserts and replacement updates. If set to true, + any empty timestamps (Timestamp(0,0)) in 'documents' or 'u' will not + be replaced by the current time and instead will be preserved as-is." + type: optionalBool + unstable: true UpdateOpEntry: description: "Parser for the entries in the 'updates' array of an update command." @@ -539,3 +545,9 @@ commands: type: EncryptionInformation optional: true unstable: true + bypassEmptyTsReplacement: + description: "Only applicable when 'update' is a replacement update. If set, any + empty timestamps (Timestamp(0, 0)) in the update will not be replaced + by the current time and instead will be preserved as-is." + type: optionalBool + unstable: true diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index 05e78ecfca6..e58146ac5cd 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -96,46 +96,6 @@ #include "mongo/util/scopeguard.h" namespace mongo::write_ops_exec { -class Atomic64Metric; -} // namespace mongo::write_ops_exec - -namespace mongo { -template <> -struct BSONObjAppendFormat<write_ops_exec::Atomic64Metric> : FormatKind<NumberLong> {}; -} // namespace mongo - - -namespace mongo::write_ops_exec { - -/** - * Atomic wrapper for long long type for Metrics. - */ -class Atomic64Metric { -public: - /** Set _value to the max of the current or newMax. */ - void setIfMax(long long newMax) { - /* Note: compareAndSwap will load into val most recent value. */ - for (long long val = _value.load(); val < newMax && !_value.compareAndSwap(&val, newMax);) { - } - } - - /** store val into value. */ - void set(long long val) { - _value.store(val); - } - - /** Return the current value. */ - long long get() const { - return _value.load(); - } - - operator long long() const { - return get(); - } - -private: - mongo::AtomicWord<long long> _value; -}; // Convention in this file: generic helpers go in the anonymous namespace. Helpers that are for a // single type of operation are static functions defined above their caller. @@ -214,7 +174,7 @@ void finishCurOp(OperationContext* opCtx, CurOp* curOp) { try { curOp->done(); auto executionTimeMicros = duration_cast<Microseconds>(curOp->elapsedTimeExcludingPauses()); - curOp->debug().executionTime = executionTimeMicros; + curOp->debug().additiveMetrics.executionTime = executionTimeMicros; recordCurOpMetrics(opCtx); Top::get(opCtx->getServiceContext()) @@ -713,7 +673,6 @@ bool getFleCrudProcessed(OperationContext* opCtx, WriteResult performInserts(OperationContext* opCtx, const write_ops::InsertCommandRequest& wholeOp, OperationSource source) { - // Insert performs its own retries, so we should only be within a WriteUnitOfWork when run in a // transaction. auto txnParticipant = TransactionParticipant::get(opCtx); @@ -772,11 +731,20 @@ WriteResult performInserts(OperationContext* opCtx, const size_t maxBatchBytes = write_ops::insertVectorMaxBytes; batch.reserve(std::min(wholeOp.getDocuments().size(), maxBatchSize)); + // If 'wholeOp.getBypassEmptyTsReplacement()' is true or if 'source' is 'kFromMigrate', set + // "bypassEmptyTsReplacement=true" for fixDocumentForInsert(). + const bool bypassEmptyTsReplacement = (source == OperationSource::kFromMigrate) || + static_cast<bool>(wholeOp.getBypassEmptyTsReplacement()); + for (auto&& doc : wholeOp.getDocuments()) { const bool isLastDoc = (&doc == &wholeOp.getDocuments().back()); bool containsDotsAndDollarsField = false; - auto fixedDoc = fixDocumentForInsert(opCtx, doc, &containsDotsAndDollarsField); + + auto fixedDoc = fixDocumentForInsert( + opCtx, doc, bypassEmptyTsReplacement, &containsDotsAndDollarsField); + const StmtId stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++); + const bool wasAlreadyExecuted = opCtx->isRetryableWrite() && txnParticipant.checkStatementExecutedNoOplogEntryFetch(opCtx, stmtId); @@ -1018,6 +986,7 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry( const write_ops::UpdateOpEntry& op, LegacyRuntimeConstants runtimeConstants, const boost::optional<BSONObj>& letParams, + const OptionalBool& bypassEmptyTsReplacement, OperationSource source, bool forgoOpCounterIncrements) { globalOpCounters.gotUpdate(); @@ -1046,6 +1015,7 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry( if (letParams) { request.setLetParameters(std::move(letParams)); } + request.setBypassEmptyTsReplacement(bypassEmptyTsReplacement); request.setStmtIds(stmtIds); request.setYieldPolicy(PlanYieldPolicy::YieldPolicy::YIELD_AUTO); request.setSource(source); @@ -1187,6 +1157,7 @@ WriteResult performUpdates(OperationContext* opCtx, singleOp, runtimeConstants, wholeOp.getLet(), + wholeOp.getBypassEmptyTsReplacement(), source, forgoOpCounterIncrements); out.results.emplace_back(reply); |
