From 9de1d61550232f370afa1b4f98bfe6aa7e2cf60f Mon Sep 17 00:00:00 2001 From: Tess Avitabile Date: Fri, 18 Jan 2019 13:35:37 -0500 Subject: SERVER-38998 Create serverStatus metrics for writeConcern --- src/mongo/db/SConscript | 3 +- src/mongo/db/commands/SConscript | 1 + src/mongo/db/commands/find_cmd.cpp | 2 +- src/mongo/db/ops/SConscript | 1 + src/mongo/db/ops/write_ops_exec.cpp | 9 ++ src/mongo/db/read_concern_stats.idl | 63 ---------- src/mongo/db/repl/SConscript | 1 + src/mongo/db/repl/oplog.cpp | 28 ++++- src/mongo/db/server_read_concern_metrics.cpp | 116 ------------------ src/mongo/db/server_read_concern_metrics.h | 71 ----------- src/mongo/db/service_entry_point_common.cpp | 2 +- src/mongo/db/stats/SConscript | 16 +++ src/mongo/db/stats/read_concern_stats.idl | 63 ++++++++++ src/mongo/db/stats/server_read_concern_metrics.cpp | 115 ++++++++++++++++++ src/mongo/db/stats/server_read_concern_metrics.h | 71 +++++++++++ .../db/stats/server_write_concern_metrics.cpp | 131 +++++++++++++++++++++ src/mongo/db/stats/server_write_concern_metrics.h | 111 +++++++++++++++++ src/mongo/db/write_concern_options.cpp | 3 + src/mongo/db/write_concern_options.h | 3 + 19 files changed, 552 insertions(+), 258 deletions(-) delete mode 100644 src/mongo/db/read_concern_stats.idl delete mode 100644 src/mongo/db/server_read_concern_metrics.cpp delete mode 100644 src/mongo/db/server_read_concern_metrics.h create mode 100644 src/mongo/db/stats/read_concern_stats.idl create mode 100644 src/mongo/db/stats/server_read_concern_metrics.cpp create mode 100644 src/mongo/db/stats/server_read_concern_metrics.h create mode 100644 src/mongo/db/stats/server_write_concern_metrics.cpp create mode 100644 src/mongo/db/stats/server_write_concern_metrics.h (limited to 'src/mongo/db') diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 03f577b3e53..aa53f6d31d7 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -682,7 +682,6 @@ env.Library( source=[ 'catalog_raii.cpp', 'retryable_writes_stats.cpp', - 'server_read_concern_metrics.cpp', 'server_transactions_metrics.cpp', 'session_catalog_mongod.cpp', 'single_transaction_stats.cpp', @@ -692,7 +691,6 @@ env.Library( 'transaction_participant.cpp', 's/recover_transaction_decision_from_local_participant.cpp', env.Idlc('session_txn_record.idl')[0], - env.Idlc('read_concern_stats.idl')[0], env.Idlc('transactions_stats.idl')[0], ], LIBDEPS=[ @@ -895,6 +893,7 @@ env.Library( '$BUILD_DIR/mongo/db/rw_concern_d', '$BUILD_DIR/mongo/db/s/sharding_api_d', '$BUILD_DIR/mongo/db/stats/counters', + '$BUILD_DIR/mongo/db/stats/server_read_concern_write_concern_metrics', '$BUILD_DIR/mongo/db/stats/top', '$BUILD_DIR/mongo/db/storage/storage_engine_lock_file', '$BUILD_DIR/mongo/db/storage/storage_engine_metadata', diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index 21d9929984a..19896af6656 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -266,6 +266,7 @@ env.Library( '$BUILD_DIR/mongo/db/query_exec', '$BUILD_DIR/mongo/db/rw_concern_d', '$BUILD_DIR/mongo/db/stats/counters', + '$BUILD_DIR/mongo/db/stats/server_read_concern_write_concern_metrics', '$BUILD_DIR/mongo/db/storage/storage_engine_common', '$BUILD_DIR/mongo/db/views/views_mongod', 'core', diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index df0bcc38423..0febcfc38c3 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -49,9 +49,9 @@ #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/s/collection_sharding_state.h" #include "mongo/db/server_parameters.h" -#include "mongo/db/server_read_concern_metrics.h" #include "mongo/db/service_context.h" #include "mongo/db/stats/counters.h" +#include "mongo/db/stats/server_read_concern_metrics.h" #include "mongo/db/transaction_participant.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/util/log.h" diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript index 2725c1219d1..3141a119179 100644 --- a/src/mongo/db/ops/SConscript +++ b/src/mongo/db/ops/SConscript @@ -17,6 +17,7 @@ env.Library( '$BUILD_DIR/mongo/db/repl/oplog', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/db/stats/counters', + '$BUILD_DIR/mongo/db/stats/server_read_concern_write_concern_metrics', '$BUILD_DIR/mongo/db/write_ops', '$BUILD_DIR/mongo/util/fail_point', '$BUILD_DIR/mongo/util/log_and_backoff', diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index bf46d4fe3eb..6a7c4528f44 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -68,6 +68,7 @@ #include "mongo/db/s/operation_sharding_state.h" #include "mongo/db/s/sharding_state.h" #include "mongo/db/stats/counters.h" +#include "mongo/db/stats/server_write_concern_metrics.h" #include "mongo/db/stats/top.h" #include "mongo/db/storage/duplicate_key_error_info.h" #include "mongo/db/transaction_participant.h" @@ -390,6 +391,8 @@ bool insertBatchAndHandleErrors(OperationContext* opCtx, opCtx, collection->getCollection(), batch.begin(), batch.end(), fromMigrate); lastOpFixer->finishedOpSuccessfully(); globalOpCounters.gotInserts(batch.size()); + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForInserts( + opCtx->getWriteConcern(), batch.size()); SingleWriteResult result; result.setN(1); @@ -414,6 +417,8 @@ bool insertBatchAndHandleErrors(OperationContext* opCtx, // for batches that failed all-at-once inserting. for (auto it = batch.begin(); it != batch.end(); ++it) { globalOpCounters.gotInsert(); + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForInsert( + opCtx->getWriteConcern()); try { writeConflictRetry(opCtx, "insert", wholeOp.getNamespace().ns(), [&] { try { @@ -545,6 +550,8 @@ WriteResult performInserts(OperationContext* opCtx, if (canContinue && !fixedDoc.isOK()) { globalOpCounters.gotInsert(); + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForInsert( + opCtx->getWriteConcern()); try { uassertStatusOK(fixedDoc.getStatus()); MONGO_UNREACHABLE; @@ -653,6 +660,7 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry(OperationContext* StmtId stmtId, const write_ops::UpdateOpEntry& op) { globalOpCounters.gotUpdate(); + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForUpdate(opCtx->getWriteConcern()); auto& curOp = *CurOp::get(opCtx); { stdx::lock_guard lk(*opCtx->getClient()); @@ -784,6 +792,7 @@ static SingleWriteResult performSingleDeleteOp(OperationContext* opCtx, !opCtx->getTxnNumber() || !op.getMulti()); globalOpCounters.gotDelete(); + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForDelete(opCtx->getWriteConcern()); auto& curOp = *CurOp::get(opCtx); { stdx::lock_guard lk(*opCtx->getClient()); diff --git a/src/mongo/db/read_concern_stats.idl b/src/mongo/db/read_concern_stats.idl deleted file mode 100644 index 60636cf0c08..00000000000 --- a/src/mongo/db/read_concern_stats.idl +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2018-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# . -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. -# - -# This IDL file describes the BSON format for ReadConcernStats, and -# handles the serialization to and deserialization from its BSON representation -# for that class. - -global: - cpp_namespace: "mongo" - -imports: - - "mongo/idl/basic_types.idl" - -structs: - - ReadConcernStats: - description: "A struct representing the section of the server status - command with information about readConcern levels used by operations" - strict: true - fields: - available: - type: long - default: 0 - linearizable: - type: long - default: 0 - local: - type: long - default: 0 - majority: - type: long - default: 0 - snapshot: - type: long - default: 0 - none: - type: long - default: 0 diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index fb8a4a18619..f78940a728d 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -27,6 +27,7 @@ env.Library( '$BUILD_DIR/mongo/db/index_d', '$BUILD_DIR/mongo/db/op_observer', '$BUILD_DIR/mongo/db/stats/counters', + '$BUILD_DIR/mongo/db/stats/server_read_concern_write_concern_metrics', '$BUILD_DIR/mongo/idl/idl_parser', ], ) diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index be070da1b4b..03bc09fd04b 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -83,6 +83,7 @@ #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" #include "mongo/db/stats/counters.h" +#include "mongo/db/stats/server_write_concern_metrics.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/db/storage/storage_options.h" #include "mongo/db/transaction_participant.h" @@ -275,6 +276,10 @@ void createIndexForApplyOps(OperationContext* opCtx, OpCounters* opCounters = opCtx->writesAreReplicated() ? &globalOpCounters : &replOpCounters; opCounters->gotInsert(); + if (opCtx->writesAreReplicated()) { + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForInsert( + opCtx->getWriteConcern()); + } const auto constraints = ReplicationCoordinator::get(opCtx)->shouldRelaxIndexConstraints(opCtx, indexNss) @@ -1102,10 +1107,9 @@ Status applyOperation_inlock(OperationContext* opCtx, // Choose opCounters based on running on standalone/primary or secondary by checking // whether writes are replicated. Atomic applyOps command is an exception, which runs // on primary/standalone but disables write replication. - OpCounters* opCounters = - (mode == repl::OplogApplication::Mode::kApplyOpsCmd || opCtx->writesAreReplicated()) - ? &globalOpCounters - : &replOpCounters; + const bool shouldUseGlobalOpCounters = + mode == repl::OplogApplication::Mode::kApplyOpsCmd || opCtx->writesAreReplicated(); + OpCounters* opCounters = shouldUseGlobalOpCounters ? &globalOpCounters : &replOpCounters; std::array names = {"ts", "t", "o", "ui", "ns", "op", "b", "o2"}; std::array fields; @@ -1317,6 +1321,10 @@ Status applyOperation_inlock(OperationContext* opCtx, wuow.commit(); for (auto entry : insertObjs) { opCounters->gotInsert(); + if (shouldUseGlobalOpCounters) { + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForInsert( + opCtx->getWriteConcern()); + } if (incrementOpsAppliedStats) { incrementOpsAppliedStats(); } @@ -1324,6 +1332,10 @@ Status applyOperation_inlock(OperationContext* opCtx, } else { // Single insert. opCounters->gotInsert(); + if (shouldUseGlobalOpCounters) { + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForInsert( + opCtx->getWriteConcern()); + } // No _id. // This indicates an issue with the upstream server: @@ -1420,6 +1432,10 @@ Status applyOperation_inlock(OperationContext* opCtx, } } else if (*opType == 'u') { opCounters->gotUpdate(); + if (shouldUseGlobalOpCounters) { + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForUpdate( + opCtx->getWriteConcern()); + } auto idField = o2["_id"]; uassert(ErrorCodes::NoSuchKey, @@ -1502,6 +1518,10 @@ Status applyOperation_inlock(OperationContext* opCtx, } } else if (*opType == 'd') { opCounters->gotDelete(); + if (shouldUseGlobalOpCounters) { + ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForDelete( + opCtx->getWriteConcern()); + } auto idField = o["_id"]; uassert(ErrorCodes::NoSuchKey, diff --git a/src/mongo/db/server_read_concern_metrics.cpp b/src/mongo/db/server_read_concern_metrics.cpp deleted file mode 100644 index 76b2a987442..00000000000 --- a/src/mongo/db/server_read_concern_metrics.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/server_read_concern_metrics.h" - -#include "mongo/db/commands/server_status.h" -#include "mongo/db/jsobj.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/read_concern_stats_gen.h" -#include "mongo/db/service_context.h" - -namespace mongo { -namespace { -const auto ServerReadConcernMetricsDecoration = - ServiceContext::declareDecoration(); -} // namespace - -ServerReadConcernMetrics* ServerReadConcernMetrics::get(ServiceContext* service) { - return &ServerReadConcernMetricsDecoration(service); -} - -ServerReadConcernMetrics* ServerReadConcernMetrics::get(OperationContext* opCtx) { - return get(opCtx->getServiceContext()); -} - -void ServerReadConcernMetrics::recordReadConcern(const repl::ReadConcernArgs& readConcernArgs) { - if (!readConcernArgs.hasOriginalLevel()) { - _noLevelCount.fetchAndAdd(1); - return; - } - - switch (readConcernArgs.getOriginalLevel()) { - case repl::ReadConcernLevel::kAvailableReadConcern: - _levelAvailableCount.fetchAndAdd(1); - break; - - case repl::ReadConcernLevel::kLinearizableReadConcern: - _levelLinearizableCount.fetchAndAdd(1); - break; - - case repl::ReadConcernLevel::kLocalReadConcern: - _levelLocalCount.fetchAndAdd(1); - break; - - case repl::ReadConcernLevel::kMajorityReadConcern: - _levelMajorityCount.fetchAndAdd(1); - break; - - case repl::ReadConcernLevel::kSnapshotReadConcern: - _levelSnapshotCount.fetchAndAdd(1); - break; - - default: - MONGO_UNREACHABLE; - } -} - -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()); -} - -namespace { -class OpReadConcernCountersSSS : public ServerStatusSection { -public: - OpReadConcernCountersSSS() : ServerStatusSection("opReadConcernCounters") {} - - ~OpReadConcernCountersSSS() override = default; - - bool includeByDefault() const override { - return true; - } - - BSONObj generateSection(OperationContext* opCtx, - const BSONElement& configElement) const override { - ReadConcernStats stats; - ServerReadConcernMetrics::get(opCtx)->updateStats(&stats, opCtx); - return stats.toBSON(); - } - -} opReadConcernCountersSSS; -} // namespace - -} // namespace mongo diff --git a/src/mongo/db/server_read_concern_metrics.h b/src/mongo/db/server_read_concern_metrics.h deleted file mode 100644 index 53644e08d78..00000000000 --- a/src/mongo/db/server_read_concern_metrics.h +++ /dev/null @@ -1,71 +0,0 @@ - -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/operation_context.h" -#include "mongo/db/read_concern_stats_gen.h" -#include "mongo/db/repl/read_concern_args.h" -#include "mongo/db/service_context.h" - -namespace mongo { - -/** - * Container for server-wide statistics on readConcern levels used by operations. - */ -class ServerReadConcernMetrics { - MONGO_DISALLOW_COPYING(ServerReadConcernMetrics); - -public: - ServerReadConcernMetrics() = default; - - static ServerReadConcernMetrics* get(ServiceContext* service); - static ServerReadConcernMetrics* get(OperationContext* opCtx); - - /** - * Updates counter for the level of 'readConcernArgs'. - */ - void recordReadConcern(const repl::ReadConcernArgs& readConcernArgs); - - /** - * Appends the accumulated stats to a readConcern stats object. - */ - void updateStats(ReadConcernStats* stats, OperationContext* opCtx); - -private: - AtomicWord _levelAvailableCount{0}; - AtomicWord _levelLinearizableCount{0}; - AtomicWord _levelLocalCount{0}; - AtomicWord _levelMajorityCount{0}; - AtomicWord _levelSnapshotCount{0}; - AtomicWord _noLevelCount{0}; -}; - -} // namespace mongo diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index e8ff824ea78..0541047348c 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -69,11 +69,11 @@ #include "mongo/db/s/operation_sharding_state.h" #include "mongo/db/s/sharded_connection_info.h" #include "mongo/db/s/sharding_state.h" -#include "mongo/db/server_read_concern_metrics.h" #include "mongo/db/service_entry_point_common.h" #include "mongo/db/session_catalog_mongod.h" #include "mongo/db/snapshot_window_util.h" #include "mongo/db/stats/counters.h" +#include "mongo/db/stats/server_read_concern_metrics.h" #include "mongo/db/stats/top.h" #include "mongo/db/transaction_coordinator_factory.h" #include "mongo/db/transaction_participant.h" diff --git a/src/mongo/db/stats/SConscript b/src/mongo/db/stats/SConscript index e8bce249241..6d2c333bf7e 100644 --- a/src/mongo/db/stats/SConscript +++ b/src/mongo/db/stats/SConscript @@ -67,6 +67,22 @@ env.Library( ], ) +env.Library( + target='server_read_concern_write_concern_metrics', + source=[ + 'server_read_concern_metrics.cpp', + 'server_write_concern_metrics.cpp', + env.Idlc('read_concern_stats.idl')[0], + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/commands/server_status', + '$BUILD_DIR/mongo/db/repl/read_concern_args', + '$BUILD_DIR/mongo/db/write_concern_options', + '$BUILD_DIR/mongo/idl/idl_parser', + ], +) + env.Library( target='fill_locker_info', source=[ diff --git a/src/mongo/db/stats/read_concern_stats.idl b/src/mongo/db/stats/read_concern_stats.idl new file mode 100644 index 00000000000..60636cf0c08 --- /dev/null +++ b/src/mongo/db/stats/read_concern_stats.idl @@ -0,0 +1,63 @@ +# Copyright (C) 2018-present MongoDB, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the Server Side Public License, version 1, +# as published by MongoDB, Inc. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Server Side Public License for more details. +# +# You should have received a copy of the Server Side Public License +# along with this program. If not, see +# . +# +# As a special exception, the copyright holders give permission to link the +# code of portions of this program with the OpenSSL library under certain +# conditions as described in each individual source file and distribute +# linked combinations including the program with the OpenSSL library. You +# must comply with the Server Side Public License in all respects for +# all of the code used other than as permitted herein. If you modify file(s) +# with this exception, you may extend this exception to your version of the +# file(s), but you are not obligated to do so. If you do not wish to do so, +# delete this exception statement from your version. If you delete this +# exception statement from all source files in the program, then also delete +# it in the license file. +# + +# This IDL file describes the BSON format for ReadConcernStats, and +# handles the serialization to and deserialization from its BSON representation +# for that class. + +global: + cpp_namespace: "mongo" + +imports: + - "mongo/idl/basic_types.idl" + +structs: + + ReadConcernStats: + description: "A struct representing the section of the server status + command with information about readConcern levels used by operations" + strict: true + fields: + available: + type: long + default: 0 + linearizable: + type: long + default: 0 + local: + type: long + default: 0 + majority: + type: long + default: 0 + snapshot: + type: long + default: 0 + none: + type: long + default: 0 diff --git a/src/mongo/db/stats/server_read_concern_metrics.cpp b/src/mongo/db/stats/server_read_concern_metrics.cpp new file mode 100644 index 00000000000..97e77079140 --- /dev/null +++ b/src/mongo/db/stats/server_read_concern_metrics.cpp @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/stats/server_read_concern_metrics.h" + +#include "mongo/db/commands/server_status.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/service_context.h" + +namespace mongo { +namespace { +const auto ServerReadConcernMetricsDecoration = + ServiceContext::declareDecoration(); +} // namespace + +ServerReadConcernMetrics* ServerReadConcernMetrics::get(ServiceContext* service) { + return &ServerReadConcernMetricsDecoration(service); +} + +ServerReadConcernMetrics* ServerReadConcernMetrics::get(OperationContext* opCtx) { + return get(opCtx->getServiceContext()); +} + +void ServerReadConcernMetrics::recordReadConcern(const repl::ReadConcernArgs& readConcernArgs) { + if (!readConcernArgs.hasOriginalLevel()) { + _noLevelCount.fetchAndAdd(1); + return; + } + + switch (readConcernArgs.getOriginalLevel()) { + case repl::ReadConcernLevel::kAvailableReadConcern: + _levelAvailableCount.fetchAndAdd(1); + break; + + case repl::ReadConcernLevel::kLinearizableReadConcern: + _levelLinearizableCount.fetchAndAdd(1); + break; + + case repl::ReadConcernLevel::kLocalReadConcern: + _levelLocalCount.fetchAndAdd(1); + break; + + case repl::ReadConcernLevel::kMajorityReadConcern: + _levelMajorityCount.fetchAndAdd(1); + break; + + case repl::ReadConcernLevel::kSnapshotReadConcern: + _levelSnapshotCount.fetchAndAdd(1); + break; + + default: + MONGO_UNREACHABLE; + } +} + +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()); +} + +namespace { +class OpReadConcernCountersSSS : public ServerStatusSection { +public: + OpReadConcernCountersSSS() : ServerStatusSection("opReadConcernCounters") {} + + ~OpReadConcernCountersSSS() override = default; + + bool includeByDefault() const override { + return true; + } + + BSONObj generateSection(OperationContext* opCtx, + const BSONElement& configElement) const override { + ReadConcernStats stats; + ServerReadConcernMetrics::get(opCtx)->updateStats(&stats, opCtx); + return stats.toBSON(); + } + +} opReadConcernCountersSSS; +} // 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 new file mode 100644 index 00000000000..a79a7cea49e --- /dev/null +++ b/src/mongo/db/stats/server_read_concern_metrics.h @@ -0,0 +1,71 @@ + +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/operation_context.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/service_context.h" +#include "mongo/db/stats/read_concern_stats_gen.h" + +namespace mongo { + +/** + * Container for server-wide statistics on readConcern levels used by operations. + */ +class ServerReadConcernMetrics { + MONGO_DISALLOW_COPYING(ServerReadConcernMetrics); + +public: + ServerReadConcernMetrics() = default; + + static ServerReadConcernMetrics* get(ServiceContext* service); + static ServerReadConcernMetrics* get(OperationContext* opCtx); + + /** + * Updates counter for the level of 'readConcernArgs'. + */ + void recordReadConcern(const repl::ReadConcernArgs& readConcernArgs); + + /** + * Appends the accumulated stats to a readConcern stats object. + */ + void updateStats(ReadConcernStats* stats, OperationContext* opCtx); + +private: + AtomicWord _levelAvailableCount{0}; + AtomicWord _levelLinearizableCount{0}; + AtomicWord _levelLocalCount{0}; + AtomicWord _levelMajorityCount{0}; + AtomicWord _levelSnapshotCount{0}; + AtomicWord _noLevelCount{0}; +}; + +} // namespace mongo diff --git a/src/mongo/db/stats/server_write_concern_metrics.cpp b/src/mongo/db/stats/server_write_concern_metrics.cpp new file mode 100644 index 00000000000..3bcf1fe99af --- /dev/null +++ b/src/mongo/db/stats/server_write_concern_metrics.cpp @@ -0,0 +1,131 @@ +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/stats/server_write_concern_metrics.h" + +#include "mongo/db/commands/server_status.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/service_context.h" + +namespace mongo { +namespace { +const auto ServerWriteConcernMetricsDecoration = + ServiceContext::declareDecoration(); +} // namespace + +ServerWriteConcernMetrics* ServerWriteConcernMetrics::get(ServiceContext* service) { + return &ServerWriteConcernMetricsDecoration(service); +} + +ServerWriteConcernMetrics* ServerWriteConcernMetrics::get(OperationContext* opCtx) { + return get(opCtx->getServiceContext()); +} + +BSONObj ServerWriteConcernMetrics::toBSON() const { + stdx::lock_guard lg(_mutex); + + BSONObjBuilder builder; + + BSONObjBuilder insertBuilder(builder.subobjStart("insert")); + _insertMetrics.toBSON(&insertBuilder); + insertBuilder.done(); + + BSONObjBuilder updateBuilder(builder.subobjStart("update")); + _updateMetrics.toBSON(&updateBuilder); + updateBuilder.done(); + + BSONObjBuilder deleteBuilder(builder.subobjStart("delete")); + _deleteMetrics.toBSON(&deleteBuilder); + deleteBuilder.done(); + + return builder.obj(); +} + +void ServerWriteConcernMetrics::WriteConcernMetricsForOperationType::recordWriteConcern( + const WriteConcernOptions& writeConcernOptions, size_t numOps) { + if (writeConcernOptions.usedDefaultW) { + noWCount += numOps; + return; + } + + if (!writeConcernOptions.wMode.empty()) { + if (writeConcernOptions.wMode == WriteConcernOptions::kMajority) { + wMajorityCount += numOps; + return; + } + + wTagCounts[writeConcernOptions.wMode] += numOps; + return; + } + + wNumCounts[writeConcernOptions.wNumNodes] += numOps; +} + +void ServerWriteConcernMetrics::WriteConcernMetricsForOperationType::toBSON( + BSONObjBuilder* builder) const { + builder->append("wmajority", wMajorityCount); + + BSONObjBuilder wNumBuilder(builder->subobjStart("wnum")); + for (auto const& pair : wNumCounts) { + wNumBuilder.append(std::to_string(pair.first), pair.second); + } + wNumBuilder.done(); + + BSONObjBuilder wTagBuilder(builder->subobjStart("wtag")); + for (auto const& pair : wTagCounts) { + wTagBuilder.append(pair.first, pair.second); + } + wTagBuilder.done(); + + builder->append("none", noWCount); +} + +namespace { +class OpWriteConcernCountersSSS : public ServerStatusSection { +public: + OpWriteConcernCountersSSS() : ServerStatusSection("opWriteConcernCounters") {} + + ~OpWriteConcernCountersSSS() override = default; + + bool includeByDefault() const override { + return true; + } + + BSONObj generateSection(OperationContext* opCtx, + const BSONElement& configElement) const override { + return ServerWriteConcernMetrics::get(opCtx)->toBSON(); + } + +} opWriteConcernCountersSSS; +} // namespace + +} // namespace mongo diff --git a/src/mongo/db/stats/server_write_concern_metrics.h b/src/mongo/db/stats/server_write_concern_metrics.h new file mode 100644 index 00000000000..355a63bff90 --- /dev/null +++ b/src/mongo/db/stats/server_write_concern_metrics.h @@ -0,0 +1,111 @@ + +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/operation_context.h" +#include "mongo/db/service_context.h" +#include "mongo/db/write_concern_options.h" + +namespace mongo { + +/** + * Container for server-wide statistics on writeConcern levels used by operations. + */ +class ServerWriteConcernMetrics { + MONGO_DISALLOW_COPYING(ServerWriteConcernMetrics); + +public: + ServerWriteConcernMetrics() = default; + + static ServerWriteConcernMetrics* get(ServiceContext* service); + static ServerWriteConcernMetrics* get(OperationContext* opCtx); + + /** + * Updates the insert metrics 'numInserts' times according to the 'w' value of + * 'writeConcernOptions'. + */ + void recordWriteConcernForInserts(const WriteConcernOptions& writeConcernOptions, + size_t numInserts) { + _insertMetrics.recordWriteConcern(writeConcernOptions, numInserts); + } + + /** + * Updates the insert metrics according to the 'w' value of 'writeConcernOptions'. + */ + void recordWriteConcernForInsert(const WriteConcernOptions& writeConcernOptions) { + recordWriteConcernForInserts(writeConcernOptions, 1); + } + + /** + * Updates the update metrics according to the 'w' value of 'writeConcernOptions'. + */ + void recordWriteConcernForUpdate(const WriteConcernOptions& writeConcernOptions) { + _updateMetrics.recordWriteConcern(writeConcernOptions); + } + + /** + * Updates the delete metrics according to the 'w' value of 'writeConcernOptions'. + */ + void recordWriteConcernForDelete(const WriteConcernOptions& writeConcernOptions) { + _deleteMetrics.recordWriteConcern(writeConcernOptions); + } + + BSONObj toBSON() const; + +private: + struct WriteConcernMetricsForOperationType { + /** + * Updates counter for the 'w' value of 'writeConcernOptions'. + */ + void recordWriteConcern(const WriteConcernOptions& writeConcernOptions, size_t numOps = 1); + + void toBSON(BSONObjBuilder* builder) const; + + // Count of operations with writeConcern w:"majority". + long long wMajorityCount = 0; + + // Count of operations without a writeConcern "w" value. + long long noWCount = 0; + + // Counts of operations with writeConcern w:. + std::map wNumCounts; + + // Counts of operations with writeConcern w:"tag". + StringMap wTagCounts; + }; + + mutable stdx::mutex _mutex; + WriteConcernMetricsForOperationType _insertMetrics; + WriteConcernMetricsForOperationType _updateMetrics; + WriteConcernMetricsForOperationType _deleteMetrics; +}; + +} // namespace mongo diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp index 4f92515f26b..96b3af194be 100644 --- a/src/mongo/db/write_concern_options.cpp +++ b/src/mongo/db/write_concern_options.cpp @@ -153,8 +153,10 @@ Status WriteConcernOptions::parse(const BSONObj& obj) { if (wEl.isNumber()) { wNumNodes = wEl.numberInt(); + usedDefaultW = false; } else if (wEl.type() == String) { wMode = wEl.valuestrsafe(); + usedDefaultW = false; } else if (wEl.eoo() || wEl.type() == jstNULL || wEl.type() == Undefined) { wNumNodes = 1; } else { @@ -174,6 +176,7 @@ StatusWith WriteConcernOptions::extractWCFromCommand( const BSONObj& cmdObj, const WriteConcernOptions& defaultWC) { WriteConcernOptions writeConcern = defaultWC; writeConcern.usedDefault = true; + writeConcern.usedDefaultW = true; if (writeConcern.wNumNodes == 0 && writeConcern.wMode.empty()) { writeConcern.wNumNodes = 1; } diff --git a/src/mongo/db/write_concern_options.h b/src/mongo/db/write_concern_options.h index 8ff5bc050c1..86b2e418ac6 100644 --- a/src/mongo/db/write_concern_options.h +++ b/src/mongo/db/write_concern_options.h @@ -120,6 +120,9 @@ public: // True if the default write concern was used. bool usedDefault = false; + + // True if the default 'w' value of w:1 was used. + bool usedDefaultW = false; }; } // namespace mongo -- cgit v1.2.1