diff options
author | Lingzhi Deng <lingzhi.deng@mongodb.com> | 2020-04-28 21:20:45 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-29 23:05:43 +0000 |
commit | f674117136f9b2699ab42a32f6f08f6c0b5a84b3 (patch) | |
tree | 35bb9b210eafa2aff85568cd245100b3a8d4e245 /src/mongo/db | |
parent | f950ce6ca8e360becb502a09b7f371b2f2c807da (diff) | |
download | mongo-f674117136f9b2699ab42a32f6f08f6c0b5a84b3.tar.gz |
SERVER-47577: readConcernCounters metric in serverStatus
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/commands.h | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/count_cmd.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/distinct.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/haystack.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/map_reduce_command_base.h | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/pipeline_command.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/repl/read_concern_args.h | 12 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/stats/read_concern_stats.idl | 37 | ||||
-rw-r--r-- | src/mongo/db/stats/server_read_concern_metrics.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/stats/server_read_concern_metrics.h | 19 |
12 files changed, 149 insertions, 37 deletions
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 37f85f0bd05..609371c6071 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -382,6 +382,14 @@ public: } /** + * Override and return true if the readConcernCounters in serverStatus should not be incremented + * on behalf of this command. + */ + virtual bool shouldAffectReadConcernCounter() const { + return false; + } + + /** * Return true if the command requires auth. */ virtual bool requiresAuth() const { diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index 3063da6955b..aab21671ba9 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -94,6 +94,10 @@ public: return ReadConcernSupportResult::allSupportedAndDefaultPermitted(); } + bool shouldAffectReadConcernCounter() const override { + return true; + } + bool supportsReadMirroring(const BSONObj&) const override { return true; } diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index 0d3c2318bff..964edb9dcb6 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -93,6 +93,10 @@ public: return ReadConcernSupportResult::allSupportedAndDefaultPermitted(); } + bool shouldAffectReadConcernCounter() const override { + return true; + } + bool supportsReadMirroring(const BSONObj&) const override { return true; } diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index d83db1ac6e2..de42810ba9b 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -169,6 +169,10 @@ public: return false; } + bool shouldAffectReadConcernCounter() const override { + return true; + } + class Invocation final : public CommandInvocation { public: Invocation(const FindCmd* definition, const OpMsgRequest& request, StringData dbName) @@ -301,8 +305,6 @@ public: CommandHelpers::handleMarkKillOnClientDisconnect(opCtx); // Although it is a command, a find command gets counted as a query. globalOpCounters.gotQuery(); - ServerReadConcernMetrics::get(opCtx)->recordReadConcern( - repl::ReadConcernArgs::get(opCtx)); // Parse the command BSON to a QueryRequest. Pass in the parsedNss in case _request.body // does not have a UUID. diff --git a/src/mongo/db/commands/haystack.cpp b/src/mongo/db/commands/haystack.cpp index 93d3df3ff65..2346e048772 100644 --- a/src/mongo/db/commands/haystack.cpp +++ b/src/mongo/db/commands/haystack.cpp @@ -85,6 +85,10 @@ public: return ReadConcernSupportResult::allSupportedAndDefaultPermitted(); } + bool shouldAffectReadConcernCounter() const override { + return true; + } + ReadWriteType getReadWriteType() const { return ReadWriteType::kRead; } diff --git a/src/mongo/db/commands/map_reduce_command_base.h b/src/mongo/db/commands/map_reduce_command_base.h index a1c45276634..bcc0870dfe5 100644 --- a/src/mongo/db/commands/map_reduce_command_base.h +++ b/src/mongo/db/commands/map_reduce_command_base.h @@ -62,6 +62,10 @@ public: {kDefaultReadConcernNotPermitted}}; } + bool shouldAffectReadConcernCounter() const override { + return true; + } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { return map_reduce_common::mrSupportsWriteConcern(cmd); } diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp index ebc251e65ea..915457281fe 100644 --- a/src/mongo/db/commands/pipeline_command.cpp +++ b/src/mongo/db/commands/pipeline_command.cpp @@ -78,6 +78,10 @@ public: this, opMsgRequest, std::move(aggregationRequest), std::move(privileges)); } + bool shouldAffectReadConcernCounter() const override { + return true; + } + class Invocation final : public CommandInvocation { public: Invocation(Command* cmd, diff --git a/src/mongo/db/repl/read_concern_args.h b/src/mongo/db/repl/read_concern_args.h index 04a2c3e131a..bdc3c5bf4eb 100644 --- a/src/mongo/db/repl/read_concern_args.h +++ b/src/mongo/db/repl/read_concern_args.h @@ -185,8 +185,18 @@ public: void setArgsAtClusterTimeForSnapshot(Timestamp ts) { invariant(_level && _level == ReadConcernLevel::kSnapshotReadConcern); invariant(!_atClusterTime); + invariant(!_atClusterTimeSelected); _afterClusterTime = boost::none; _atClusterTime = LogicalTime(ts); + _atClusterTimeSelected = true; + } + + /** + * Return whether an atClusterTime has been selected by the server for a snapshot read. This + * function returns false if the atClusterTime was specified by the client. + */ + bool wasAtClusterTimeSelected() const { + return _atClusterTimeSelected; } private: @@ -223,6 +233,8 @@ private: bool _specified; ReadWriteConcernProvenance _provenance; + + bool _atClusterTimeSelected = false; }; } // namespace repl diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index 55959347ec9..1e9f51a137a 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -615,13 +615,21 @@ void invokeWithSessionCheckedOut(OperationContext* opCtx, if (!opCtx->getClient()->isInDirectClient()) { const auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx); + auto command = invocation->definition(); + // Record readConcern usages for commands run inside transactions after unstashing the + // transaction resources. + if (command->shouldAffectReadConcernCounter() && opCtx->inMultiDocumentTransaction()) { + ServerReadConcernMetrics::get(opCtx)->recordReadConcern(readConcernArgs, + true /* isTransaction */); + } + // For replica sets, we do not receive the readConcernArgs of our parent transaction // statements until we unstash the transaction resources. The below check is necessary to // ensure commands, including those occurring after the first statement in their respective // transactions, are checked for readConcern support. Presently, only `create` and // `createIndexes` do not support readConcern inside transactions. // TODO(SERVER-46971): Consider how to extend this check to other commands. - auto cmdName = invocation->definition()->getName(); + auto cmdName = command->getName(); auto readConcernSupport = invocation->supportsReadConcern(readConcernArgs.getLevel()); if (readConcernArgs.hasLevel() && (cmdName == "create"_sd || cmdName == "createIndexes"_sd)) { @@ -714,6 +722,15 @@ bool runCommandImpl(OperationContext* opCtx, const bool shouldWaitForWriteConcern = invocation->supportsWriteConcern() || command->getLogicalOp() == LogicalOp::opGetMore; + // Record readConcern usages for commands run outside of transactions, excluding DBDirectClient. + // For commands inside a transaction, they inherit the readConcern from the transaction. So we + // will record their readConcern usages after we have unstashed the transaction resources. + if (!opCtx->getClient()->isInDirectClient() && command->shouldAffectReadConcernCounter() && + !opCtx->inMultiDocumentTransaction()) { + ServerReadConcernMetrics::get(opCtx)->recordReadConcern(repl::ReadConcernArgs::get(opCtx), + false /* isTransaction */); + } + if (shouldWaitForWriteConcern) { auto lastOpBeforeRun = repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp(); @@ -1436,7 +1453,11 @@ DbResponse receivedQuery(OperationContext* opCtx, const ServiceEntryPointCommon::Hooks& behaviors) { invariant(!nss.isCommand()); globalOpCounters.gotQuery(); - ServerReadConcernMetrics::get(opCtx)->recordReadConcern(repl::ReadConcernArgs::get(opCtx)); + + if (!opCtx->getClient()->isInDirectClient()) { + ServerReadConcernMetrics::get(opCtx)->recordReadConcern(repl::ReadConcernArgs::get(opCtx), + false /* isTransaction */); + } DbMessage d(m); QueryMessage q(d); diff --git a/src/mongo/db/stats/read_concern_stats.idl b/src/mongo/db/stats/read_concern_stats.idl index 60636cf0c08..30ec3c47a05 100644 --- a/src/mongo/db/stats/read_concern_stats.idl +++ b/src/mongo/db/stats/read_concern_stats.idl @@ -38,26 +38,45 @@ imports: structs: - ReadConcernStats: - description: "A struct representing the section of the server status - command with information about readConcern levels used by operations" + SnapshotOps: + description: "A struct representing the number of operations used with snapshot readConcern" strict: true fields: - available: + withClusterTime: type: long default: 0 - linearizable: + withoutClusterTime: + type: long + default: 0 + + ReadConcernOps: + description: "A struct representing readConcern level usages by read operations" + strict: true + fields: + none: type: long default: 0 local: type: long default: 0 + available: + type: long + optional: true majority: type: long default: 0 snapshot: + type: SnapshotOps + linearizable: type: long - default: 0 - none: - type: long - default: 0 + optional: true + + ReadConcernStats: + description: "A struct representing the section of the server status + command with information about readConcern levels used by operations" + strict: true + fields: + nonTransactionOps: + type: ReadConcernOps + transactionOps: + type: ReadConcernOps diff --git a/src/mongo/db/stats/server_read_concern_metrics.cpp b/src/mongo/db/stats/server_read_concern_metrics.cpp index 1dd4c9fff8e..a29b7ab781a 100644 --- a/src/mongo/db/stats/server_read_concern_metrics.cpp +++ b/src/mongo/db/stats/server_read_concern_metrics.cpp @@ -50,31 +50,41 @@ ServerReadConcernMetrics* ServerReadConcernMetrics::get(OperationContext* opCtx) return get(opCtx->getServiceContext()); } -void ServerReadConcernMetrics::recordReadConcern(const repl::ReadConcernArgs& readConcernArgs) { +void ServerReadConcernMetrics::recordReadConcern(const repl::ReadConcernArgs& readConcernArgs, + bool isTransaction) { + auto& ops = isTransaction ? _transactionOps : _nonTransactionOps; + if (!readConcernArgs.hasLevel()) { - _noLevelCount.fetchAndAdd(1); + ops.noLevelCount.fetchAndAdd(1); return; } switch (readConcernArgs.getLevel()) { case repl::ReadConcernLevel::kAvailableReadConcern: - _levelAvailableCount.fetchAndAdd(1); + invariant(!isTransaction); + ops.levelAvailableCount.fetchAndAdd(1); break; case repl::ReadConcernLevel::kLinearizableReadConcern: - _levelLinearizableCount.fetchAndAdd(1); + invariant(!isTransaction); + ops.levelLinearizableCount.fetchAndAdd(1); break; case repl::ReadConcernLevel::kLocalReadConcern: - _levelLocalCount.fetchAndAdd(1); + ops.levelLocalCount.fetchAndAdd(1); break; case repl::ReadConcernLevel::kMajorityReadConcern: - _levelMajorityCount.fetchAndAdd(1); + ops.levelMajorityCount.fetchAndAdd(1); break; case repl::ReadConcernLevel::kSnapshotReadConcern: - _levelSnapshotCount.fetchAndAdd(1); + if (readConcernArgs.getArgsAtClusterTime() && + !readConcernArgs.wasAtClusterTimeSelected()) { + ops.atClusterTimeCount.fetchAndAdd(1); + } else { + ops.levelSnapshotCount.fetchAndAdd(1); + } break; default: @@ -83,20 +93,35 @@ void ServerReadConcernMetrics::recordReadConcern(const repl::ReadConcernArgs& re } void ServerReadConcernMetrics::updateStats(ReadConcernStats* stats, OperationContext* opCtx) { - stats->setAvailable(_levelAvailableCount.load()); - stats->setLinearizable(_levelLinearizableCount.load()); - stats->setLocal(_levelLocalCount.load()); - stats->setMajority(_levelMajorityCount.load()); - stats->setSnapshot(_levelSnapshotCount.load()); - stats->setNone(_noLevelCount.load()); + ReadConcernOps nonTransactionOps; + SnapshotOps nonTransactionSnapshotOps; + nonTransactionSnapshotOps.setWithoutClusterTime(_nonTransactionOps.levelSnapshotCount.load()); + nonTransactionSnapshotOps.setWithClusterTime(_nonTransactionOps.atClusterTimeCount.load()); + nonTransactionOps.setNone(_nonTransactionOps.noLevelCount.load()); + nonTransactionOps.setAvailable(_nonTransactionOps.levelAvailableCount.load()); + nonTransactionOps.setLinearizable(_nonTransactionOps.levelLinearizableCount.load()); + nonTransactionOps.setLocal(_nonTransactionOps.levelLocalCount.load()); + nonTransactionOps.setMajority(_nonTransactionOps.levelMajorityCount.load()); + nonTransactionOps.setSnapshot(nonTransactionSnapshotOps); + stats->setNonTransactionOps(nonTransactionOps); + + ReadConcernOps transactionOps; + SnapshotOps transactionSnapshotOps; + transactionSnapshotOps.setWithoutClusterTime(_transactionOps.levelSnapshotCount.load()); + transactionSnapshotOps.setWithClusterTime(_transactionOps.atClusterTimeCount.load()); + transactionOps.setNone(_transactionOps.noLevelCount.load()); + transactionOps.setLocal(_transactionOps.levelLocalCount.load()); + transactionOps.setMajority(_transactionOps.levelMajorityCount.load()); + transactionOps.setSnapshot(transactionSnapshotOps); + stats->setTransactionOps(transactionOps); } namespace { -class OpReadConcernCountersSSS : public ServerStatusSection { +class ReadConcernCountersSSS : public ServerStatusSection { public: - OpReadConcernCountersSSS() : ServerStatusSection("opReadConcernCounters") {} + ReadConcernCountersSSS() : ServerStatusSection("readConcernCounters") {} - ~OpReadConcernCountersSSS() override = default; + ~ReadConcernCountersSSS() override = default; bool includeByDefault() const override { return true; @@ -109,7 +134,7 @@ public: return stats.toBSON(); } -} opReadConcernCountersSSS; +} ReadConcernCountersSSS; } // namespace } // namespace mongo diff --git a/src/mongo/db/stats/server_read_concern_metrics.h b/src/mongo/db/stats/server_read_concern_metrics.h index 1a247f79df6..7782b959bfd 100644 --- a/src/mongo/db/stats/server_read_concern_metrics.h +++ b/src/mongo/db/stats/server_read_concern_metrics.h @@ -52,7 +52,7 @@ public: /** * Updates counter for the level of 'readConcernArgs'. */ - void recordReadConcern(const repl::ReadConcernArgs& readConcernArgs); + void recordReadConcern(const repl::ReadConcernArgs& readConcernArgs, bool isTransaction); /** * Appends the accumulated stats to a readConcern stats object. @@ -60,12 +60,17 @@ public: void updateStats(ReadConcernStats* stats, OperationContext* opCtx); private: - AtomicWord<unsigned long long> _levelAvailableCount{0}; - AtomicWord<unsigned long long> _levelLinearizableCount{0}; - AtomicWord<unsigned long long> _levelLocalCount{0}; - AtomicWord<unsigned long long> _levelMajorityCount{0}; - AtomicWord<unsigned long long> _levelSnapshotCount{0}; - AtomicWord<unsigned long long> _noLevelCount{0}; + struct readConcernCounters { + AtomicWord<unsigned long long> levelAvailableCount{0}; + AtomicWord<unsigned long long> levelLinearizableCount{0}; + AtomicWord<unsigned long long> levelLocalCount{0}; + AtomicWord<unsigned long long> levelMajorityCount{0}; + AtomicWord<unsigned long long> levelSnapshotCount{0}; + AtomicWord<unsigned long long> atClusterTimeCount{0}; + AtomicWord<unsigned long long> noLevelCount{0}; + }; + readConcernCounters _nonTransactionOps; + readConcernCounters _transactionOps; }; } // namespace mongo |