diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2018-11-14 09:00:30 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2018-11-16 03:26:19 -0500 |
commit | 943b0f7294b1f30483cc9d0fa4e870b00a68465d (patch) | |
tree | 8673dae5e032f4abf6aaba537acaf0a88f54bfeb /src | |
parent | 72789f5739982af1cbdb1dd4fa181c4924f657b3 (diff) | |
download | mongo-943b0f7294b1f30483cc9d0fa4e870b00a68465d.tar.gz |
SERVER-37665 Get rid of the 'checkOutSession' parameter of OperationContextSession
This simplifies the behaviour of the class and moves all the check-out
decision taking to happen in the only consumer - the endpoint.
Also renames OperationContextSessionMongoD to MongoDOperationContextSession
in order to be in sync with the naming nomenclature of SessionCatalog and
MongoDSessionCatalog.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/op_observer_impl_test.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/operation_context_session_mongod.cpp | 58 | ||||
-rw-r--r-- | src/mongo/db/operation_context_session_mongod.h | 69 | ||||
-rw-r--r-- | src/mongo/db/repl/apply_ops.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/repl/do_txn_test.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/repl/transaction_oplog_application.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/s/session_catalog_migration_destination_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/s/txn_two_phase_commit_cmds.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/session_catalog.cpp | 61 | ||||
-rw-r--r-- | src/mongo/db/session_catalog.h | 2 | ||||
-rw-r--r-- | src/mongo/db/session_catalog_mongod.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/session_catalog_mongod.h | 28 | ||||
-rw-r--r-- | src/mongo/db/session_catalog_test.cpp | 52 | ||||
-rw-r--r-- | src/mongo/db/transaction_participant_test.cpp | 24 | ||||
-rw-r--r-- | src/mongo/dbtests/storage_timestamp_tests.cpp | 6 |
17 files changed, 127 insertions, 234 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index c3c544a7cce..909faaaab47 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -680,7 +680,6 @@ env.Library( target='catalog_raii', source=[ 'catalog_raii.cpp', - 'operation_context_session_mongod.cpp', 'retryable_writes_stats.cpp', 'server_transactions_metrics.cpp', 'session_catalog_mongod.cpp', diff --git a/src/mongo/db/op_observer_impl_test.cpp b/src/mongo/db/op_observer_impl_test.cpp index 0c2501cd6f0..6bfd5a8ec48 100644 --- a/src/mongo/db/op_observer_impl_test.cpp +++ b/src/mongo/db/op_observer_impl_test.cpp @@ -40,7 +40,6 @@ #include "mongo/db/logical_clock.h" #include "mongo/db/logical_time_validator.h" #include "mongo/db/op_observer_impl.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/oplog_interface_local.h" #include "mongo/db/repl/repl_client_info.h" @@ -540,7 +539,8 @@ public: _times.emplace(opCtx()); opCtx()->setLogicalSessionId(session()->getSessionId()); opCtx()->setTxnNumber(txnNum()); - _sessionCheckout = std::make_unique<OperationContextSessionMongod>(opCtx(), true); + + _sessionCheckout = std::make_unique<MongoDOperationContextSession>(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); txnParticipant->beginOrContinue(*opCtx()->getTxnNumber(), false, true); } @@ -627,7 +627,7 @@ private: boost::optional<ScopedSession> _session; ServiceContext::UniqueOperationContext _opCtx; boost::optional<ExposeOpObserverTimes::ReservedTimes> _times; - std::unique_ptr<OperationContextSessionMongod> _sessionCheckout; + std::unique_ptr<MongoDOperationContextSession> _sessionCheckout; TxnNumber _txnNum = 0; }; diff --git a/src/mongo/db/operation_context_session_mongod.cpp b/src/mongo/db/operation_context_session_mongod.cpp deleted file mode 100644 index 6622a5f4e0d..00000000000 --- a/src/mongo/db/operation_context_session_mongod.cpp +++ /dev/null @@ -1,58 +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 - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * 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/operation_context_session_mongod.h" - -#include "mongo/db/transaction_participant.h" - -namespace mongo { - -OperationContextSessionMongod::OperationContextSessionMongod(OperationContext* opCtx, - bool shouldCheckOutSession) - : _operationContextSession(opCtx, shouldCheckOutSession) { - if (shouldCheckOutSession && !opCtx->getClient()->isInDirectClient()) { - const auto txnParticipant = TransactionParticipant::get(opCtx); - txnParticipant->refreshFromStorageIfNeeded(opCtx); - } -} - -OperationContextSessionMongodWithoutRefresh::OperationContextSessionMongodWithoutRefresh( - OperationContext* opCtx) - : _operationContextSession(opCtx, true /* checkout */) { - invariant(!opCtx->getClient()->isInDirectClient()); - const auto clientTxnNumber = *opCtx->getTxnNumber(); - - const auto txnParticipant = TransactionParticipant::get(opCtx); - txnParticipant->beginOrContinueTransactionUnconditionally(clientTxnNumber); -} - -} // namespace mongo diff --git a/src/mongo/db/operation_context_session_mongod.h b/src/mongo/db/operation_context_session_mongod.h deleted file mode 100644 index bdbea720dbf..00000000000 --- a/src/mongo/db/operation_context_session_mongod.h +++ /dev/null @@ -1,69 +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 - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * 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 <boost/optional.hpp> - -#include "mongo/db/session_catalog.h" - -namespace mongo { - -class OperationContext; - -/** - * Scoped object, which checks out the session specified in the passed operation context and stores - * it for later access by the command. The session is installed at construction time and is removed - * at destruction. - */ -class OperationContextSessionMongod { -public: - OperationContextSessionMongod(OperationContext* opCtx, bool shouldCheckOutSession); - -private: - OperationContextSession _operationContextSession; -}; - -/** - * Similar to OperationContextSessionMongod, but marks the TransactionParticipant as valid without - * refreshing from disk and starts a new transaction unconditionally. - * - * NOTE: Only used by the replication oplog application logic on secondaries in order to replay - * prepared transactions. - */ -class OperationContextSessionMongodWithoutRefresh { -public: - OperationContextSessionMongodWithoutRefresh(OperationContext* opCtx); - -private: - OperationContextSession _operationContextSession; -}; - -} // namespace mongo diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp index ea7e62763a0..9edb6be9bc8 100644 --- a/src/mongo/db/repl/apply_ops.cpp +++ b/src/mongo/db/repl/apply_ops.cpp @@ -49,10 +49,10 @@ #include "mongo/db/matcher/matcher.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/query/collation/collation_spec.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/service_context.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/transaction_participant.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/util/fail_point_service.h" @@ -313,7 +313,7 @@ Status _applyPrepareTransaction(OperationContext* opCtx, // The write on transaction table may be applied concurrently, so refreshing state // from disk may read that write, causing starting a new transaction on an existing // txnNumber. Thus, we start a new transaction without refreshing state from disk. - OperationContextSessionMongodWithoutRefresh sessionCheckout(opCtx); + MongoDOperationContextSessionWithoutRefresh sessionCheckout(opCtx); auto transaction = TransactionParticipant::get(opCtx); transaction->unstashTransactionResources(opCtx, "prepareTransaction"); diff --git a/src/mongo/db/repl/do_txn_test.cpp b/src/mongo/db/repl/do_txn_test.cpp index 1820b17e78d..66d3017b415 100644 --- a/src/mongo/db/repl/do_txn_test.cpp +++ b/src/mongo/db/repl/do_txn_test.cpp @@ -35,7 +35,6 @@ #include "mongo/db/client.h" #include "mongo/db/op_observer_noop.h" #include "mongo/db/op_observer_registry.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/repl/do_txn.h" #include "mongo/db/repl/oplog_interface_local.h" #include "mongo/db/repl/repl_client_info.h" @@ -117,7 +116,7 @@ protected: OpObserverMock* _opObserver = nullptr; std::unique_ptr<StorageInterface> _storage; ServiceContext::UniqueOperationContext _opCtx; - boost::optional<OperationContextSessionMongod> _ocs; + boost::optional<MongoDOperationContextSession> _ocs; }; void DoTxnTest::setUp() { @@ -156,7 +155,7 @@ void DoTxnTest::setUp() { // Set up the transaction and session. _opCtx->setLogicalSessionId(makeLogicalSessionIdForTest()); _opCtx->setTxnNumber(0); // TxnNumber can always be 0 because we have a new session. - _ocs.emplace(_opCtx.get(), true /* checkOutSession */); + _ocs.emplace(_opCtx.get()); auto txnParticipant = TransactionParticipant::get(opCtx()); txnParticipant->beginOrContinue(*opCtx()->getTxnNumber(), false, true); diff --git a/src/mongo/db/repl/transaction_oplog_application.cpp b/src/mongo/db/repl/transaction_oplog_application.cpp index 00460ed68f2..52f99c6fdbf 100644 --- a/src/mongo/db/repl/transaction_oplog_application.cpp +++ b/src/mongo/db/repl/transaction_oplog_application.cpp @@ -28,13 +28,13 @@ * it in the license file. */ -#include "mongo/db/repl/transaction_oplog_application.h" - #include "mongo/platform/basic.h" +#include "mongo/db/repl/transaction_oplog_application.h" + #include "mongo/db/commands/txn_cmds_gen.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/repl/apply_ops.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/transaction_history_iterator.h" #include "mongo/db/transaction_participant.h" @@ -89,7 +89,7 @@ Status applyCommitTransaction(OperationContext* opCtx, // The write on transaction table may be applied concurrently, so refreshing state // from disk may read that write, causing starting a new transaction on an existing // txnNumber. Thus, we start a new transaction without refreshing state from disk. - OperationContextSessionMongodWithoutRefresh sessionCheckout(opCtx); + MongoDOperationContextSessionWithoutRefresh sessionCheckout(opCtx); auto transaction = TransactionParticipant::get(opCtx); invariant(transaction); @@ -123,7 +123,7 @@ Status applyAbortTransaction(OperationContext* opCtx, // The write on transaction table may be applied concurrently, so refreshing state // from disk may read that write, causing starting a new transaction on an existing // txnNumber. Thus, we start a new transaction without refreshing state from disk. - OperationContextSessionMongodWithoutRefresh sessionCheckout(opCtx); + MongoDOperationContextSessionWithoutRefresh sessionCheckout(opCtx); auto transaction = TransactionParticipant::get(opCtx); transaction->unstashTransactionResources(opCtx, "abortTransaction"); diff --git a/src/mongo/db/s/session_catalog_migration_destination_test.cpp b/src/mongo/db/s/session_catalog_migration_destination_test.cpp index f929156353a..95e806a0afd 100644 --- a/src/mongo/db/s/session_catalog_migration_destination_test.cpp +++ b/src/mongo/db/s/session_catalog_migration_destination_test.cpp @@ -37,14 +37,12 @@ #include "mongo/db/initialize_operation_session_info.h" #include "mongo/db/logical_session_cache_noop.h" #include "mongo/db/logical_session_id.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/ops/write_ops_exec.h" #include "mongo/db/ops/write_ops_gen.h" #include "mongo/db/repl/oplog_entry.h" #include "mongo/db/s/migration_session_id.h" #include "mongo/db/s/session_catalog_migration_destination.h" #include "mongo/db/server_options.h" -#include "mongo/db/session_catalog.h" #include "mongo/db/session_catalog_mongod.h" #include "mongo/db/session_txn_record_gen.h" #include "mongo/db/transaction_history_iterator.h" @@ -250,7 +248,7 @@ public: // requests with txnNumbers aren't allowed. To get around this, we have to manually set // up the session state and perform the insert. initializeOperationSessionInfo(innerOpCtx.get(), insertBuilder.obj(), true, true, true); - OperationContextSessionMongod sessionTxnState(innerOpCtx.get(), true); + MongoDOperationContextSession sessionTxnState(innerOpCtx.get()); auto txnParticipant = TransactionParticipant::get(innerOpCtx.get()); txnParticipant->beginOrContinue(*sessionInfo.getTxnNumber(), boost::none, boost::none); diff --git a/src/mongo/db/s/txn_two_phase_commit_cmds.cpp b/src/mongo/db/s/txn_two_phase_commit_cmds.cpp index 7edb6c2ee4a..270d3a31cf8 100644 --- a/src/mongo/db/s/txn_two_phase_commit_cmds.cpp +++ b/src/mongo/db/s/txn_two_phase_commit_cmds.cpp @@ -35,9 +35,9 @@ #include "mongo/client/remote_command_targeter.h" #include "mongo/db/commands.h" #include "mongo/db/commands/txn_two_phase_commit_cmds_gen.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/s/sharding_state.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/transaction_coordinator_service.h" #include "mongo/db/transaction_participant.h" #include "mongo/executor/task_executor.h" diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index 292bbf6db7b..c695741d003 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -57,7 +57,6 @@ #include "mongo/db/logical_session_id.h" #include "mongo/db/logical_session_id_helpers.h" #include "mongo/db/logical_time_validator.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/ops/write_ops.h" #include "mongo/db/ops/write_ops_exec.h" #include "mongo/db/query/find.h" @@ -70,6 +69,7 @@ #include "mongo/db/s/sharded_connection_info.h" #include "mongo/db/s/sharding_state.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/top.h" @@ -576,9 +576,11 @@ void execCommandDatabase(OperationContext* opCtx, // handles the appropriate state management for both multi-statement transactions and // retryable writes. Currently, only requests with a transaction number will check out the // session. - const bool shouldCheckOutSession = static_cast<bool>(sessionOptions.getTxnNumber()) && - !shouldCommandSkipSessionCheckout(command->getName()); - OperationContextSessionMongod sessionTxnState(opCtx, shouldCheckOutSession); + boost::optional<MongoDOperationContextSession> sessionTxnState; + const bool shouldCheckOutSession = + sessionOptions.getTxnNumber() && !shouldCommandSkipSessionCheckout(command->getName()); + if (shouldCheckOutSession) + sessionTxnState.emplace(opCtx); std::unique_ptr<MaintenanceModeSetter> mmSetter; diff --git a/src/mongo/db/session_catalog.cpp b/src/mongo/db/session_catalog.cpp index 70049de30a4..bc6d09710a5 100644 --- a/src/mongo/db/session_catalog.cpp +++ b/src/mongo/db/session_catalog.cpp @@ -186,55 +186,44 @@ void SessionCatalog::_releaseSession(const LogicalSessionId& lsid, } } -OperationContextSession::OperationContextSession(OperationContext* opCtx, bool checkOutSession) - : _opCtx(opCtx) { - if (!opCtx->getLogicalSessionId()) { - return; - } - - if (!checkOutSession) { - return; - } - +OperationContextSession::OperationContextSession(OperationContext* opCtx) : _opCtx(opCtx) { auto& checkedOutSession = operationSessionDecoration(opCtx); - if (!checkedOutSession) { - auto sessionTransactionTable = SessionCatalog::get(opCtx); - auto scopedCheckedOutSession = sessionTransactionTable->checkOutSession(opCtx); - // We acquire a Client lock here to guard the construction of this session so that - // references to this session are safe to use while the lock is held. - stdx::lock_guard<Client> lk(*opCtx->getClient()); - checkedOutSession.emplace(std::move(scopedCheckedOutSession)); - } else { - // The only reason to be trying to check out a session when you already have a session - // checked out is if you're in DBDirectClient. + if (checkedOutSession) { + // The only case where a session can be checked-out more than once is due to DBDirectClient + // reentrancy invariant(opCtx->getClient()->isInDirectClient()); return; } - const auto session = checkedOutSession->get(); - invariant(opCtx->getLogicalSessionId() == session->getSessionId()); + const auto catalog = SessionCatalog::get(opCtx); + auto scopedCheckedOutSession = catalog->checkOutSession(opCtx); + + // We acquire a Client lock here to guard the construction of this session so that references to + // this session are safe to use while the lock is held + stdx::lock_guard<Client> lk(*opCtx->getClient()); + checkedOutSession.emplace(std::move(scopedCheckedOutSession)); } OperationContextSession::~OperationContextSession() { - // Only release the checked out session at the end of the top-level request from the client, - // not at the end of a nested DBDirectClient call. + // Only release the checked out session at the end of the top-level request from the client, not + // at the end of a nested DBDirectClient call if (_opCtx->getClient()->isInDirectClient()) { return; } auto& checkedOutSession = operationSessionDecoration(_opCtx); - if (checkedOutSession) { - // Removing the checkedOutSession from the OperationContext must be done under the Client - // lock, but destruction of the checkedOutSession must not be, as it takes the - // SessionCatalog mutex, and other code may take the Client lock while holding that mutex. - stdx::unique_lock<Client> lk(*_opCtx->getClient()); - ScopedCheckedOutSession sessionToDelete(std::move(checkedOutSession.get())); - - // This destroys the moved-from ScopedCheckedOutSession, and must be done within the client - // lock. - checkedOutSession = boost::none; - lk.unlock(); - } + if (!checkedOutSession) + return; + + // Removing the checkedOutSession from the OperationContext must be done under the Client lock, + // but destruction of the checkedOutSession must not be, as it takes the SessionCatalog mutex, + // and other code may take the Client lock while holding that mutex. + stdx::unique_lock<Client> lk(*_opCtx->getClient()); + ScopedCheckedOutSession sessionToDelete(std::move(checkedOutSession.get())); + + // This destroys the moved-from ScopedCheckedOutSession, and must be done within the client lock + checkedOutSession = boost::none; + lk.unlock(); } Session* OperationContextSession::get(OperationContext* opCtx) { diff --git a/src/mongo/db/session_catalog.h b/src/mongo/db/session_catalog.h index 8e2a35d8b8d..020d1fa5c06 100644 --- a/src/mongo/db/session_catalog.h +++ b/src/mongo/db/session_catalog.h @@ -250,7 +250,7 @@ class OperationContextSession { MONGO_DISALLOW_COPYING(OperationContextSession); public: - OperationContextSession(OperationContext* opCtx, bool checkOutSession); + OperationContextSession(OperationContext* opCtx); ~OperationContextSession(); /** diff --git a/src/mongo/db/session_catalog_mongod.cpp b/src/mongo/db/session_catalog_mongod.cpp index 1c844bd78f0..5ea8173ca05 100644 --- a/src/mongo/db/session_catalog_mongod.cpp +++ b/src/mongo/db/session_catalog_mongod.cpp @@ -171,4 +171,23 @@ void MongoDSessionCatalog::invalidateSessions(OperationContext* opCtx, })); } + +MongoDOperationContextSession::MongoDOperationContextSession(OperationContext* opCtx) + : _operationContextSession(opCtx) { + if (!opCtx->getClient()->isInDirectClient()) { + const auto txnParticipant = TransactionParticipant::get(opCtx); + txnParticipant->refreshFromStorageIfNeeded(opCtx); + } +} + +MongoDOperationContextSessionWithoutRefresh::MongoDOperationContextSessionWithoutRefresh( + OperationContext* opCtx) + : _operationContextSession(opCtx) { + invariant(!opCtx->getClient()->isInDirectClient()); + const auto clientTxnNumber = *opCtx->getTxnNumber(); + + const auto txnParticipant = TransactionParticipant::get(opCtx); + txnParticipant->beginOrContinueTransactionUnconditionally(clientTxnNumber); +} + } // namespace mongo diff --git a/src/mongo/db/session_catalog_mongod.h b/src/mongo/db/session_catalog_mongod.h index 4496c8b17f3..c71e0dce076 100644 --- a/src/mongo/db/session_catalog_mongod.h +++ b/src/mongo/db/session_catalog_mongod.h @@ -65,4 +65,32 @@ public: boost::optional<BSONObj> singleSessionDoc); }; +/** + * Scoped object, which checks out the session specified in the passed operation context and stores + * it for later access by the command. The session is installed at construction time and is removed + * at destruction. + */ +class MongoDOperationContextSession { +public: + MongoDOperationContextSession(OperationContext* opCtx); + +private: + OperationContextSession _operationContextSession; +}; + +/** + * Similar to MongoDOperationContextSession, but marks the TransactionParticipant as valid without + * refreshing from disk and starts a new transaction unconditionally. + * + * NOTE: Only used by the replication oplog application logic on secondaries in order to replay + * prepared transactions. + */ +class MongoDOperationContextSessionWithoutRefresh { +public: + MongoDOperationContextSessionWithoutRefresh(OperationContext* opCtx); + +private: + OperationContextSession _operationContextSession; +}; + } // namespace mongo diff --git a/src/mongo/db/session_catalog_test.cpp b/src/mongo/db/session_catalog_test.cpp index 1f8312b6e69..09bf4c7e878 100644 --- a/src/mongo/db/session_catalog_test.cpp +++ b/src/mongo/db/session_catalog_test.cpp @@ -92,21 +92,12 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, OperationContextCheckedOutSession) { const TxnNumber txnNum = 20; _opCtx->setTxnNumber(txnNum); - OperationContextSession ocs(_opCtx, true); + OperationContextSession ocs(_opCtx); auto session = OperationContextSession::get(_opCtx); ASSERT(session); ASSERT_EQ(*_opCtx->getLogicalSessionId(), session->getSessionId()); } -TEST_F(SessionCatalogTestWithDefaultOpCtx, OperationContextNonCheckedOutSession) { - _opCtx->setLogicalSessionId(makeLogicalSessionIdForTest()); - - OperationContextSession ocs(_opCtx, false); - auto session = OperationContextSession::get(_opCtx); - - ASSERT(!session); -} - TEST_F(SessionCatalogTestWithDefaultOpCtx, GetOrCreateNonExistentSession) { const auto lsid = makeLogicalSessionIdForTest(); auto scopedSession = catalog()->getOrCreateSession(_opCtx, lsid); @@ -120,7 +111,7 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, GetOrCreateSessionAfterCheckOutSessio _opCtx->setLogicalSessionId(lsid); boost::optional<OperationContextSession> ocs; - ocs.emplace(_opCtx, true); + ocs.emplace(_opCtx); stdx::async(stdx::launch::async, [&] { ThreadClient tc(getGlobalServiceContext()); @@ -149,11 +140,11 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, NestedOperationContextSession) { _opCtx->setLogicalSessionId(makeLogicalSessionIdForTest()); { - OperationContextSession outerScopedSession(_opCtx, true); + OperationContextSession outerScopedSession(_opCtx); { DirectClientSetter inDirectClient(_opCtx); - OperationContextSession innerScopedSession(_opCtx, true); + OperationContextSession innerScopedSession(_opCtx); auto session = OperationContextSession::get(_opCtx); ASSERT(session); @@ -214,7 +205,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsNotCheckedOut) { { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(opCtx.get(), true); + OperationContextSession unusedOperationContextSession(opCtx.get()); } auto killToken = catalog()->killSession(lsid); @@ -224,9 +215,8 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsNotCheckedOut) { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); opCtx->setDeadlineAfterNowBy(Milliseconds(10), ErrorCodes::MaxTimeMSExpired); - ASSERT_THROWS_CODE(OperationContextSession(opCtx.get(), true), - AssertionException, - ErrorCodes::MaxTimeMSExpired); + ASSERT_THROWS_CODE( + OperationContextSession(opCtx.get()), AssertionException, ErrorCodes::MaxTimeMSExpired); } // Schedule a separate "regular operation" thread, which will block on checking-out the session, @@ -236,7 +226,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsNotCheckedOut) { auto sideOpCtx = Client::getCurrent()->makeOperationContext(); sideOpCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(sideOpCtx.get(), true); + OperationContextSession unusedOperationContextSession(sideOpCtx.get()); }); ASSERT(stdx::future_status::ready != future.wait_for(Milliseconds(10).toSystemDuration())); @@ -251,7 +241,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsNotCheckedOut) { { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(opCtx.get(), true); + OperationContextSession unusedOperationContextSession(opCtx.get()); } // Make sure the "regular operation" eventually is able to proceed and use the just killed @@ -266,7 +256,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsCheckedOut) { // Create the session so there is something to kill auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); - OperationContextSession operationContextSession(opCtx.get(), true); + OperationContextSession operationContextSession(opCtx.get()); auto killToken = catalog()->killSession(lsid); @@ -281,7 +271,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsCheckedOut) { sideOpCtx->setLogicalSessionId(lsid); sideOpCtx->setDeadlineAfterNowBy(Milliseconds(10), ErrorCodes::MaxTimeMSExpired); - OperationContextSession unusedOperationContextSession(sideOpCtx.get(), true); + OperationContextSession unusedOperationContextSession(sideOpCtx.get()); }); ASSERT_THROWS_CODE(future.get(), AssertionException, ErrorCodes::MaxTimeMSExpired); @@ -294,9 +284,8 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsCheckedOut) { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); opCtx->setDeadlineAfterNowBy(Milliseconds(10), ErrorCodes::MaxTimeMSExpired); - ASSERT_THROWS_CODE(OperationContextSession(opCtx.get(), true), - AssertionException, - ErrorCodes::MaxTimeMSExpired); + ASSERT_THROWS_CODE( + OperationContextSession(opCtx.get()), AssertionException, ErrorCodes::MaxTimeMSExpired); } // Schedule a separate "regular operation" thread, which will block on checking-out the session, @@ -306,7 +295,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsCheckedOut) { auto sideOpCtx = Client::getCurrent()->makeOperationContext(); sideOpCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(sideOpCtx.get(), true); + OperationContextSession unusedOperationContextSession(sideOpCtx.get()); }); ASSERT(stdx::future_status::ready != future.wait_for(Milliseconds(10).toSystemDuration())); @@ -321,7 +310,7 @@ TEST_F(SessionCatalogTest, KillSessionWhenSessionIsCheckedOut) { { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(opCtx.get(), true); + OperationContextSession unusedOperationContextSession(opCtx.get()); } // Make sure the "regular operation" eventually is able to proceed and use the just killed @@ -336,7 +325,7 @@ TEST_F(SessionCatalogTest, MarkSessionAsKilledThrowsWhenCalledTwice) { { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(opCtx.get(), true); + OperationContextSession unusedOperationContextSession(opCtx.get()); } auto killToken = catalog()->killSession(lsid); @@ -351,9 +340,8 @@ TEST_F(SessionCatalogTest, MarkSessionAsKilledThrowsWhenCalledTwice) { auto opCtx = makeOperationContext(); opCtx->setLogicalSessionId(lsid); opCtx->setDeadlineAfterNowBy(Milliseconds(10), ErrorCodes::MaxTimeMSExpired); - ASSERT_THROWS_CODE(OperationContextSession(opCtx.get(), true), - AssertionException, - ErrorCodes::MaxTimeMSExpired); + ASSERT_THROWS_CODE( + OperationContextSession(opCtx.get()), AssertionException, ErrorCodes::MaxTimeMSExpired); } // Finish "killing" the session so the SessionCatalog destructor doesn't complain @@ -388,7 +376,7 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, KillSessionsThroughScanSessions) { auto sideOpCtx = Client::getCurrent()->makeOperationContext(); sideOpCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(sideOpCtx.get(), true); + OperationContextSession unusedOperationContextSession(sideOpCtx.get()); firstUseOfTheSessionReachedBarrier.countDownAndWait(); ASSERT_THROWS_CODE(sideOpCtx->sleepFor(Hours{6}), @@ -400,7 +388,7 @@ TEST_F(SessionCatalogTestWithDefaultOpCtx, KillSessionsThroughScanSessions) { auto sideOpCtx = Client::getCurrent()->makeOperationContext(); sideOpCtx->setLogicalSessionId(lsid); - OperationContextSession unusedOperationContextSession(sideOpCtx.get(), true); + OperationContextSession unusedOperationContextSession(sideOpCtx.get()); } })); } diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp index d6b64bc960b..1518edff739 100644 --- a/src/mongo/db/transaction_participant_test.cpp +++ b/src/mongo/db/transaction_participant_test.cpp @@ -36,7 +36,6 @@ #include "mongo/db/op_observer_noop.h" #include "mongo/db/op_observer_registry.h" #include "mongo/db/operation_context.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/repl/mock_repl_coord_server_fixture.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/oplog_entry.h" @@ -272,8 +271,8 @@ protected: runFunctionFromDifferentOpCtx(func); } - std::unique_ptr<OperationContextSessionMongod> checkOutSession() { - auto opCtxSession = std::make_unique<OperationContextSessionMongod>(opCtx(), true); + std::unique_ptr<MongoDOperationContextSession> checkOutSession() { + auto opCtxSession = std::make_unique<MongoDOperationContextSession>(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); txnParticipant->beginOrContinue(*opCtx()->getTxnNumber(), false, true); return opCtxSession; @@ -318,7 +317,7 @@ TEST_F(TxnParticipantTest, TransactionThrowsLockTimeoutIfLockIsUnavailable) { newOpCtx.get()->setLogicalSessionId(newSessionId); newOpCtx.get()->setTxnNumber(newTxnNum); - OperationContextSessionMongod newOpCtxSession(newOpCtx.get(), true); + MongoDOperationContextSession newOpCtxSession(newOpCtx.get()); auto newTxnParticipant = TransactionParticipant::get(newOpCtx.get()); newTxnParticipant->beginOrContinue(newTxnNum, false, true); newTxnParticipant->unstashTransactionResources(newOpCtx.get(), "insert"); @@ -1077,7 +1076,7 @@ TEST_F(TxnParticipantTest, ContinuingATransactionWithNoResourcesAborts) { checkOutSession(); // Check out the session again for a new operation. - OperationContextSessionMongod sessionCheckout(opCtx(), true); + MongoDOperationContextSession sessionCheckout(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); ASSERT_THROWS_CODE( @@ -1278,7 +1277,7 @@ DEATH_TEST_F(TxnParticipantTest, AbortIsIllegalDuringCommittingPreparedTransacti } TEST_F(TxnParticipantTest, CannotContinueNonExistentTransaction) { - OperationContextSessionMongod opCtxSession(opCtx(), true); + MongoDOperationContextSession opCtxSession(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); ASSERT_THROWS_CODE( txnParticipant->beginOrContinue(*opCtx()->getTxnNumber(), false, boost::none), @@ -1333,7 +1332,7 @@ TEST_F(TxnParticipantTest, StashInNestedSessionIsANoop) { { // Make it look like we're in a DBDirectClient running a nested operation. DirectClientSetter inDirectClient(opCtx()); - OperationContextSessionMongod innerScopedSession(opCtx(), true); + MongoDOperationContextSession innerScopedSession(opCtx()); txnParticipant->stashTransactionResources(opCtx()); @@ -1346,7 +1345,6 @@ TEST_F(TxnParticipantTest, StashInNestedSessionIsANoop) { } TEST_F(TxnParticipantTest, UnstashInNestedSessionIsANoop) { - auto outerScopedSession = checkOutSession(); Locker* originalLocker = opCtx()->lockState(); @@ -1366,7 +1364,7 @@ TEST_F(TxnParticipantTest, UnstashInNestedSessionIsANoop) { { // Make it look like we're in a DBDirectClient running a nested operation. DirectClientSetter inDirectClient(opCtx()); - OperationContextSessionMongod innerScopedSession(opCtx(), true); + MongoDOperationContextSession innerScopedSession(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); txnParticipant->unstashTransactionResources(opCtx(), "find"); @@ -1451,7 +1449,7 @@ protected: } void cannotSpecifyStartTransactionOnStartedRetryableWrite() { - OperationContextSessionMongod opCtxSession(opCtx(), true); + MongoDOperationContextSession opCtxSession(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); txnParticipant->beginOrContinue(*opCtx()->getTxnNumber(), boost::none, boost::none); @@ -2895,7 +2893,7 @@ TEST_F(TransactionsMetricsTest, ReportUnstashedResourcesForARetryableWrite) { ASSERT(opCtx()->lockState()); ASSERT(opCtx()->recoveryUnit()); - OperationContextSessionMongod opCtxSession(opCtx(), true); + MongoDOperationContextSession opCtxSession(opCtx()); auto txnParticipant = TransactionParticipant::get(opCtx()); txnParticipant->beginOrContinue(*opCtx()->getTxnNumber(), boost::none, boost::none); txnParticipant->unstashTransactionResources(opCtx(), "find"); @@ -3571,7 +3569,7 @@ TEST_F(TxnParticipantTest, WhenOldestTSRemovedNextOldestBecomesNewOldest) { newOpCtx.get()->setLogicalSessionId(newSessionId); newOpCtx.get()->setTxnNumber(newTxnNum); - OperationContextSessionMongod newOpCtxSession(newOpCtx.get(), true); + MongoDOperationContextSession newOpCtxSession(newOpCtx.get()); auto newTxnParticipant = TransactionParticipant::get(newOpCtx.get()); newTxnParticipant->beginOrContinue(newTxnNum, false, true); newTxnParticipant->unstashTransactionResources(newOpCtx.get(), "prepareTransaction"); @@ -3633,7 +3631,7 @@ TEST_F(TxnParticipantTest, ReturnNullTimestampIfNoOldestActiveTimestamp) { newOpCtx.get()->setLogicalSessionId(newSessionId); newOpCtx.get()->setTxnNumber(newTxnNum); - OperationContextSessionMongod newOpCtxSession(newOpCtx.get(), true); + MongoDOperationContextSession newOpCtxSession(newOpCtx.get()); auto newTxnParticipant = TransactionParticipant::get(newOpCtx.get()); newTxnParticipant->beginOrContinue(newTxnNum, false, true); newTxnParticipant->unstashTransactionResources(newOpCtx.get(), "prepareTransaction"); diff --git a/src/mongo/dbtests/storage_timestamp_tests.cpp b/src/mongo/dbtests/storage_timestamp_tests.cpp index 468474393a1..7688df65a5c 100644 --- a/src/mongo/dbtests/storage_timestamp_tests.cpp +++ b/src/mongo/dbtests/storage_timestamp_tests.cpp @@ -53,7 +53,6 @@ #include "mongo/db/logical_clock.h" #include "mongo/db/multi_key_path_tracker.h" #include "mongo/db/op_observer_registry.h" -#include "mongo/db/operation_context_session_mongod.h" #include "mongo/db/repl/apply_ops.h" #include "mongo/db/repl/drop_pending_collection_reaper.h" #include "mongo/db/repl/multiapplier.h" @@ -2498,7 +2497,7 @@ public: _opCtx->setLogicalSessionId(sessionId); _opCtx->setTxnNumber(26); - ocs = std::make_unique<OperationContextSessionMongod>(_opCtx, true); + ocs.emplace(_opCtx); auto txnParticipant = TransactionParticipant::get(_opCtx); ASSERT(txnParticipant); @@ -2539,7 +2538,8 @@ protected: Timestamp presentTs; Timestamp beforeTxnTs; Timestamp commitEntryTs; - std::unique_ptr<OperationContextSessionMongod> ocs; + + boost::optional<MongoDOperationContextSession> ocs; }; class MultiDocumentTransaction : public MultiDocumentTransactionTest { |