summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r--src/mongo/db/ops/SConscript2
-rw-r--r--src/mongo/db/ops/insert.cpp7
-rw-r--r--src/mongo/db/ops/insert.h1
-rw-r--r--src/mongo/db/ops/parsed_update.cpp1
-rw-r--r--src/mongo/db/ops/update_request.h10
-rw-r--r--src/mongo/db/ops/write_ops.cpp6
-rw-r--r--src/mongo/db/ops/write_ops.idl12
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp57
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);