diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2019-11-01 22:00:41 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-11-01 22:00:41 +0000 |
commit | 7692bc0ed90792bd74d45fd8a1070baecdc4f9eb (patch) | |
tree | cac01e72f5164ec9619db4bc1f13841445edfaeb /src/mongo | |
parent | e5340534df81238e454ce7d3afbb7883115f2c53 (diff) | |
download | mongo-7692bc0ed90792bd74d45fd8a1070baecdc4f9eb.tar.gz |
SERVER-40372 Track transaction size
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/server_transactions_metrics.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/server_transactions_metrics.h | 10 | ||||
-rw-r--r-- | src/mongo/db/transaction_metrics_observer.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/transaction_metrics_observer.h | 7 | ||||
-rw-r--r-- | src/mongo/db/transaction_participant.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/transaction_participant.h | 4 | ||||
-rw-r--r-- | src/mongo/db/transactions_stats.idl | 17 | ||||
-rw-r--r-- | src/mongo/shell/session.js | 34 |
8 files changed, 100 insertions, 20 deletions
diff --git a/src/mongo/db/server_transactions_metrics.cpp b/src/mongo/db/server_transactions_metrics.cpp index 1daa320782d..a51ecc0345c 100644 --- a/src/mongo/db/server_transactions_metrics.cpp +++ b/src/mongo/db/server_transactions_metrics.cpp @@ -149,6 +149,18 @@ void ServerTransactionsMetrics::decrementCurrentPrepared() { _currentPrepared.fetchAndSubtract(1); } +void ServerTransactionsMetrics::updateLastTransaction(size_t operationCount, + size_t oplogOperationBytes, + BSONObj writeConcern) { + stdx::lock_guard<Latch> lg(_mutex); + if (!_lastCommittedTransaction) { + _lastCommittedTransaction = LastCommittedTransaction(); + } + _lastCommittedTransaction->setOperationCount(operationCount); + _lastCommittedTransaction->setOplogOperationBytes(oplogOperationBytes); + _lastCommittedTransaction->setWriteConcern(std::move(writeConcern)); +} + void ServerTransactionsMetrics::updateStats(TransactionsStats* stats) { stats->setCurrentActive(_currentActive.load()); stats->setCurrentInactive(_currentInactive.load()); @@ -160,6 +172,11 @@ void ServerTransactionsMetrics::updateStats(TransactionsStats* stats) { stats->setTotalPreparedThenCommitted(_totalPreparedThenCommitted.load()); stats->setTotalPreparedThenAborted(_totalPreparedThenAborted.load()); stats->setCurrentPrepared(_currentPrepared.load()); + + stdx::lock_guard<Latch> lg(_mutex); + if (_lastCommittedTransaction) { + stats->setLastCommittedTransaction(*_lastCommittedTransaction); + } } namespace { diff --git a/src/mongo/db/server_transactions_metrics.h b/src/mongo/db/server_transactions_metrics.h index 250b2c41931..78523e5fa36 100644 --- a/src/mongo/db/server_transactions_metrics.h +++ b/src/mongo/db/server_transactions_metrics.h @@ -36,6 +36,7 @@ #include "mongo/db/repl/optime.h" #include "mongo/db/service_context.h" #include "mongo/db/transactions_stats_gen.h" +#include "mongo/platform/mutex.h" #include "mongo/util/concurrency/with_lock.h" namespace mongo { @@ -87,6 +88,10 @@ public: void incrementCurrentPrepared(); void decrementCurrentPrepared(); + void updateLastTransaction(size_t operationCount, + size_t oplogOperationBytes, + BSONObj writeConcern); + /** * Appends the accumulated stats to a transactions stats object. */ @@ -122,6 +127,11 @@ private: // The current number of transactions in the prepared state. AtomicWord<unsigned long long> _currentPrepared{0}; + + // Protects member variables below. + mutable Mutex _mutex = MONGO_MAKE_LATCH("ServerTransactionsMetrics::_mutex"); + + boost::optional<LastCommittedTransaction> _lastCommittedTransaction; }; } // namespace mongo diff --git a/src/mongo/db/transaction_metrics_observer.cpp b/src/mongo/db/transaction_metrics_observer.cpp index e1b36d971bd..24bc70d6dea 100644 --- a/src/mongo/db/transaction_metrics_observer.cpp +++ b/src/mongo/db/transaction_metrics_observer.cpp @@ -92,9 +92,12 @@ void TransactionMetricsObserver::onUnstash(ServerTransactionsMetrics* serverTran serverTransactionsMetrics->decrementCurrentInactive(); } -void TransactionMetricsObserver::onCommit(ServerTransactionsMetrics* serverTransactionsMetrics, +void TransactionMetricsObserver::onCommit(OperationContext* opCtx, + ServerTransactionsMetrics* serverTransactionsMetrics, TickSource* tickSource, - Top* top) { + Top* top, + size_t operationCount, + size_t oplogOperationBytes) { // // Per transaction metrics. // @@ -118,6 +121,11 @@ void TransactionMetricsObserver::onCommit(ServerTransactionsMetrics* serverTrans serverTransactionsMetrics->decrementCurrentPrepared(); } + serverTransactionsMetrics->updateLastTransaction( + operationCount, + oplogOperationBytes, + opCtx->getWriteConcern().usedDefault ? BSONObj() : opCtx->getWriteConcern().toBSON()); + auto duration = durationCount<Microseconds>(_singleTransactionStats.getDuration(tickSource, curTick)); top->incrementGlobalTransactionLatencyStats(static_cast<uint64_t>(duration)); diff --git a/src/mongo/db/transaction_metrics_observer.h b/src/mongo/db/transaction_metrics_observer.h index 634792198c0..c985beb7af0 100644 --- a/src/mongo/db/transaction_metrics_observer.h +++ b/src/mongo/db/transaction_metrics_observer.h @@ -70,9 +70,12 @@ public: /** * Updates relevant metrics when a transaction commits. */ - void onCommit(ServerTransactionsMetrics* serverTransactionsMetrics, + void onCommit(OperationContext* opCtx, + ServerTransactionsMetrics* serverTransactionsMetrics, TickSource* tickSource, - Top* top); + Top* top, + size_t operationCount, + size_t oplogOperationBytes); /** * Updates relevant metrics when a transaction aborts. diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp index 65613550dc8..01d378e2d88 100644 --- a/src/mongo/db/transaction_participant.cpp +++ b/src/mongo/db/transaction_participant.cpp @@ -1239,13 +1239,15 @@ void TransactionParticipant::Participant::commitUnpreparedTransaction(OperationC auto wc = opCtx->getWriteConcern(); auto needsNoopWrite = txnOps.empty() && !opCtx->getWriteConcern().usedDefault; + const size_t operationCount = p().transactionOperations.size(); + const size_t oplogOperationBytes = p().transactionOperationBytes; clearOperationsInMemory(opCtx); try { // Once committing we cannot throw an exception. UninterruptibleLockGuard noInterrupt(opCtx->lockState()); _commitStorageTransaction(opCtx); - _finishCommitTransaction(opCtx); + _finishCommitTransaction(opCtx, operationCount, oplogOperationBytes); } catch (...) { // It is illegal for committing a transaction to fail for any reason, other than an // invalid command, so we crash instead. @@ -1367,9 +1369,11 @@ void TransactionParticipant::Participant::commitPreparedTransaction( opObserver->onPreparedTransactionCommit( opCtx, commitOplogSlot, commitTimestamp, retrieveCompletedTransactionOperations(opCtx)); + const size_t operationCount = p().transactionOperations.size(); + const size_t oplogOperationBytes = p().transactionOperationBytes; clearOperationsInMemory(opCtx); - _finishCommitTransaction(opCtx); + _finishCommitTransaction(opCtx, operationCount, oplogOperationBytes); } catch (...) { // It is illegal for committing a prepared transaction to fail for any reason, other than an // invalid command, so we crash instead. @@ -1400,15 +1404,20 @@ void TransactionParticipant::Participant::_commitStorageTransaction(OperationCon std::terminate(); } -void TransactionParticipant::Participant::_finishCommitTransaction(OperationContext* opCtx) { +void TransactionParticipant::Participant::_finishCommitTransaction(OperationContext* opCtx, + size_t operationCount, + size_t oplogOperationBytes) { { auto tickSource = opCtx->getServiceContext()->getTickSource(); stdx::lock_guard<Client> lk(*opCtx->getClient()); o(lk).txnState.transitionTo(TransactionState::kCommitted); - o(lk).transactionMetricsObserver.onCommit(ServerTransactionsMetrics::get(opCtx), + o(lk).transactionMetricsObserver.onCommit(opCtx, + ServerTransactionsMetrics::get(opCtx), tickSource, - &Top::get(getGlobalServiceContext())); + &Top::get(getGlobalServiceContext()), + operationCount, + oplogOperationBytes); o(lk).transactionMetricsObserver.onTransactionOperation( opCtx, CurOp::get(opCtx)->debug().additiveMetrics, o().txnState.isPrepared()); } diff --git a/src/mongo/db/transaction_participant.h b/src/mongo/db/transaction_participant.h index ccad3a30085..a2dece48562 100644 --- a/src/mongo/db/transaction_participant.h +++ b/src/mongo/db/transaction_participant.h @@ -642,7 +642,9 @@ public: // Finishes committing the multi-document transaction after the storage-transaction has been // committed, the oplog entry has been inserted into the oplog, and the transactions table // has been updated. - void _finishCommitTransaction(OperationContext* opCtx); + void _finishCommitTransaction(OperationContext* opCtx, + size_t operationCount, + size_t oplogOperationBytes); // Commits the storage-transaction on the OperationContext. // diff --git a/src/mongo/db/transactions_stats.idl b/src/mongo/db/transactions_stats.idl index c2a269d4a79..eb55df77a74 100644 --- a/src/mongo/db/transactions_stats.idl +++ b/src/mongo/db/transactions_stats.idl @@ -39,6 +39,20 @@ imports: structs: + LastCommittedTransaction: + description: "A struct representing the server status subsection on + the last committed transaction" + strict: true + fields: + operationCount: + type: long + default: 0 + oplogOperationBytes: + type: long + default: 0 + writeConcern: + type: object + TransactionsStats: description: "A struct representing the section of the server status command with information about transactions" @@ -83,3 +97,6 @@ structs: currentPrepared: type: long default: 0 + lastCommittedTransaction: + type: LastCommittedTransaction + optional: true diff --git a/src/mongo/shell/session.js b/src/mongo/shell/session.js index 0f6eb11323a..4be01d2895e 100644 --- a/src/mongo/shell/session.js +++ b/src/mongo/shell/session.js @@ -718,6 +718,20 @@ var { return endTransaction("abortTransaction", driverSession); }; + this.getTxnWriteConcern = function getTxnWriteConcern(driverSession) { + // If a writeConcern is not specified from the default transaction options, it will be + // inherited from the session. + let writeConcern = undefined; + const sessionAwareClient = driverSession._getSessionAwareClient(); + if (sessionAwareClient.getWriteConcern(driverSession) !== undefined) { + writeConcern = sessionAwareClient.getWriteConcern(driverSession); + } + if (_txnOptions.getTxnWriteConcern() !== undefined) { + writeConcern = _txnOptions.getTxnWriteConcern(); + } + return writeConcern; + }; + const endTransaction = (commandName, driverSession) => { // If commitTransaction or abortTransaction is the first statement in a // transaction, it should not send a command to the server and should mark the @@ -732,22 +746,18 @@ var { } let cmd = {[commandName]: 1, txnNumber: this.handle.getTxnNumber()}; - // writeConcern should only be specified on commit or abort. If a writeConcern is - // not specified from the default transaction options, it will be inherited from - // the session. - const sessionAwareClient = driverSession._getSessionAwareClient(); - if (sessionAwareClient.getWriteConcern(driverSession) !== undefined) { - cmd.writeConcern = sessionAwareClient.getWriteConcern(driverSession); - } - if (_txnOptions.getTxnWriteConcern() !== undefined) { - cmd.writeConcern = _txnOptions.getTxnWriteConcern(); + // writeConcern should only be specified on commit or abort. + const writeConcern = driverSession._serverSession.getTxnWriteConcern(driverSession); + if (writeConcern !== undefined) { + cmd.writeConcern = writeConcern; } // If commit or abort raises an error, the transaction's state should still change. let res; try { // run command against the admin database. - res = sessionAwareClient.runCommand(driverSession, "admin", cmd, 0); + res = driverSession._getSessionAwareClient().runCommand( + driverSession, "admin", cmd, 0); } finally { if (commandName === "commitTransaction") { setTxnState("committed"); @@ -874,6 +884,10 @@ var { return this._serverSession.getTxnNumber(); }; + this.getTxnWriteConcern_forTesting = function getTxnWriteConcern_forTesting() { + return this._serverSession.getTxnWriteConcern(this); + }; + this.setTxnNumber_forTesting = function setTxnNumber_forTesting(newTxnNumber) { this._serverSession.setTxnNumber_forTesting(newTxnNumber); }; |