diff options
19 files changed, 250 insertions, 159 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 202e70c044a..0f78df550db 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -643,24 +643,25 @@ env.Library( 'operation_context_session_mongod.cpp', 'retryable_writes_stats.cpp', 'server_transactions_metrics.cpp', - 'session.cpp', + 'session_catalog_mongod.cpp', 'session_catalog.cpp', + 'session.cpp', 'single_transaction_stats.cpp', 'transaction_coordinator_factory.cpp', + 'transaction_history_iterator.cpp', 'transaction_metrics_observer.cpp', 'transaction_participant.cpp', - 'transaction_history_iterator.cpp', env.Idlc('session_txn_record.idl')[0], - env.Idlc('transactions_stats.idl')[0], env.Idlc('transaction_commit_decision.idl')[0], + env.Idlc('transactions_stats.idl')[0], ], LIBDEPS=[ - '$BUILD_DIR/mongo/db/stats/fill_locker_info', '$BUILD_DIR/mongo/idl/idl_parser', 'catalog/collection', - 'catalog/database', 'catalog/database_holder', + 'catalog/database', 'catalog/uuid_catalog', + 'commands/test_commands_enabled', 'commands/txn_cmd_request', 'concurrency/lock_manager', 'curop_failpoint_helpers', @@ -673,9 +674,9 @@ env.Library( 'repl/oplog_entry', 'repl/oplog_shim', 's/sharding_api_d', - "stats/top", + 'stats/fill_locker_info', 'views/views', - '$BUILD_DIR/mongo/db/commands/test_commands_enabled', + "stats/top", ], LIBDEPS_PRIVATE=[ 'commands/server_status', @@ -1960,15 +1961,14 @@ env.Library( ) env.CppUnitTest( - target='sessions_test', + target='session_catalog_test', source=[ 'session_catalog_test.cpp', ], LIBDEPS=[ - '$BUILD_DIR/mongo/client/read_preference', - '$BUILD_DIR/mongo/db/auth/authmocks', - '$BUILD_DIR/mongo/db/repl/mock_repl_coord_server_fixture', - 'query_exec', + 'auth/authmocks', + 'catalog_raii', + 'repl/mock_repl_coord_server_fixture', ], ) diff --git a/src/mongo/db/kill_sessions_local.cpp b/src/mongo/db/kill_sessions_local.cpp index e76b2b8db65..99efaa2e91d 100644 --- a/src/mongo/db/kill_sessions_local.cpp +++ b/src/mongo/db/kill_sessions_local.cpp @@ -37,27 +37,37 @@ #include "mongo/db/kill_sessions_common.h" #include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" -#include "mongo/db/session.h" #include "mongo/db/session_catalog.h" +#include "mongo/db/session_killer.h" #include "mongo/db/transaction_participant.h" #include "mongo/util/log.h" namespace mongo { namespace { -void killSessionsLocalKillCursors(OperationContext* opCtx, const SessionKiller::Matcher& matcher) { - auto res = CursorManager::killCursorsWithMatchingSessions(opCtx, matcher); - uassertStatusOK(res.first); +void killSessionsAction(OperationContext* opCtx, + const SessionKiller::Matcher& matcher, + const SessionCatalog::ScanSessionsCallbackFn& killSessionFn) { + const auto catalog = SessionCatalog::get(opCtx); + + catalog->scanSessions(opCtx, matcher, [&](OperationContext* opCtx, Session* session) { + // TODO (SERVER-33850): Rename KillAllSessionsByPattern and + // ScopedKillAllSessionsByPatternImpersonator to not refer to session kill + const KillAllSessionsByPattern* pattern = matcher.match(session->getSessionId()); + invariant(pattern); + + ScopedKillAllSessionsByPatternImpersonator impersonator(opCtx, *pattern); + killSessionFn(opCtx, session); + }); } + } // namespace void killSessionsLocalKillTransactions(OperationContext* opCtx, const SessionKiller::Matcher& matcher) { - SessionCatalog::get(opCtx)->scanSessions( - opCtx, matcher, [](OperationContext* opCtx, Session* session) { - TransactionParticipant::getFromNonCheckedOutSession(session) - ->abortArbitraryTransaction(); - }); + killSessionsAction(opCtx, matcher, [](OperationContext* opCtx, Session* session) { + TransactionParticipant::getFromNonCheckedOutSession(session)->abortArbitraryTransaction(); + }); } SessionKiller::Result killSessionsLocal(OperationContext* opCtx, @@ -65,43 +75,44 @@ SessionKiller::Result killSessionsLocal(OperationContext* opCtx, SessionKiller::UniformRandomBitGenerator* urbg) { killSessionsLocalKillTransactions(opCtx, matcher); uassertStatusOK(killSessionsLocalKillOps(opCtx, matcher)); - killSessionsLocalKillCursors(opCtx, matcher); + + auto res = CursorManager::killCursorsWithMatchingSessions(opCtx, matcher); + uassertStatusOK(res.first); + return {std::vector<HostAndPort>{}}; } void killAllExpiredTransactions(OperationContext* opCtx) { SessionKiller::Matcher matcherAllSessions( KillAllSessionsByPatternSet{makeKillAllSessionsByPattern(opCtx)}); - SessionCatalog::get(opCtx)->scanSessions( - opCtx, matcherAllSessions, [](OperationContext* opCtx, Session* session) { - try { - TransactionParticipant::getFromNonCheckedOutSession(session) - ->abortArbitraryTransactionIfExpired(); - } catch (const DBException& ex) { - Status status = ex.toStatus(); - std::string errmsg = str::stream() - << "May have failed to abort expired transaction with session id (lsid) '" - << session->getSessionId() << "'." - << " Caused by: " << status; - warning() << errmsg; - } - }); + killSessionsAction(opCtx, matcherAllSessions, [](OperationContext* opCtx, Session* session) { + try { + TransactionParticipant::getFromNonCheckedOutSession(session) + ->abortArbitraryTransactionIfExpired(); + } catch (const DBException& ex) { + Status status = ex.toStatus(); + std::string errmsg = str::stream() + << "May have failed to abort expired transaction with session id (lsid) '" + << session->getSessionId() << "'." + << " Caused by: " << status; + warning() << errmsg; + } + }); } void killSessionsLocalShutdownAllTransactions(OperationContext* opCtx) { SessionKiller::Matcher matcherAllSessions( KillAllSessionsByPatternSet{makeKillAllSessionsByPattern(opCtx)}); - SessionCatalog::get(opCtx)->scanSessions( - opCtx, matcherAllSessions, [](OperationContext* opCtx, Session* session) { - TransactionParticipant::getFromNonCheckedOutSession(session)->shutdown(); - }); + killSessionsAction(opCtx, matcherAllSessions, [](OperationContext* opCtx, Session* session) { + TransactionParticipant::getFromNonCheckedOutSession(session)->shutdown(); + }); } void killSessionsLocalAbortOrYieldAllTransactions( OperationContext* opCtx, std::vector<std::pair<Locker*, Locker::LockSnapshot>>* yieldedLocks) { SessionKiller::Matcher matcherAllSessions( KillAllSessionsByPatternSet{makeKillAllSessionsByPattern(opCtx)}); - SessionCatalog::get(opCtx)->scanSessions( + killSessionsAction( opCtx, matcherAllSessions, [yieldedLocks](OperationContext* opCtx, Session* session) { TransactionParticipant::getFromNonCheckedOutSession(session) ->abortOrYieldArbitraryTransaction(yieldedLocks); diff --git a/src/mongo/db/op_observer_impl_test.cpp b/src/mongo/db/op_observer_impl_test.cpp index c5d202cee71..f6cb972a78e 100644 --- a/src/mongo/db/op_observer_impl_test.cpp +++ b/src/mongo/db/op_observer_impl_test.cpp @@ -26,8 +26,8 @@ * it in the license file. */ +#include "mongo/platform/basic.h" -#include "mongo/db/op_observer_impl.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/client.h" #include "mongo/db/concurrency/locker_noop.h" @@ -37,13 +37,14 @@ #include "mongo/db/keys_collection_manager.h" #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" #include "mongo/db/repl/replication_coordinator_mock.h" #include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h" #include "mongo/db/transaction_participant.h" #include "mongo/s/config_server_test_fixture.h" @@ -301,9 +302,15 @@ public: void setUp() override { OpObserverTest::setUp(); auto opCtx = cc().makeOperationContext(); + + MongoDSessionCatalog::onStepUp(opCtx.get()); + } + + void tearDown() override { auto sessionCatalog = SessionCatalog::get(getServiceContext()); sessionCatalog->reset_forTest(); - sessionCatalog->onStepUp(opCtx.get()); + + OpObserverTest::tearDown(); } /** diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 8465cd9f70b..5c0f5e5e36d 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -129,8 +129,6 @@ env.Library( ], ) - - env.Library( target='bgsync', source=[ diff --git a/src/mongo/db/repl/do_txn_test.cpp b/src/mongo/db/repl/do_txn_test.cpp index 91642f9f951..2bd573e78e1 100644 --- a/src/mongo/db/repl/do_txn_test.cpp +++ b/src/mongo/db/repl/do_txn_test.cpp @@ -25,6 +25,7 @@ * 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/catalog/collection_options.h" @@ -40,7 +41,7 @@ #include "mongo/db/repl/storage_interface_impl.h" #include "mongo/db/s/op_observer_sharding_impl.h" #include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/transaction_participant.h" #include "mongo/logger/logger.h" #include "mongo/rpc/get_status_from_command_result.h" @@ -121,7 +122,7 @@ void DoTxnTest::setUp() { // Set up mongod. ServiceContextMongoDTest::setUp(); - auto service = getServiceContext(); + const auto service = getServiceContext(); _opCtx = cc().makeOperationContext(); // Set up ReplicationCoordinator and create oplog. @@ -134,8 +135,7 @@ void DoTxnTest::setUp() { ASSERT_OK(replCoord->setFollowerMode(MemberState::RS_PRIMARY)); // Set up session catalog - SessionCatalog::get(service)->reset_forTest(); - SessionCatalog::get(service)->onStepUp(_opCtx.get()); + MongoDSessionCatalog::onStepUp(_opCtx.get()); // Need the OpObserverImpl in the registry in order for doTxn to work. OpObserverRegistry* opObserverRegistry = @@ -166,6 +166,8 @@ void DoTxnTest::tearDown() { _storage = {}; _opObserver = nullptr; + SessionCatalog::get(getServiceContext())->reset_forTest(); + // Reset default log level in case it was changed. logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogComponent::kReplication, logger::LogSeverity::Debug(0)); diff --git a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp index 3af514b94e4..8e7934e2912 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -78,7 +78,7 @@ #include "mongo/db/server_options.h" #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/db/system_index.h" #include "mongo/executor/network_connection_hook.h" @@ -95,7 +95,6 @@ #include "mongo/stdx/memory.h" #include "mongo/stdx/thread.h" #include "mongo/transport/service_entry_point.h" -#include "mongo/transport/session.h" #include "mongo/util/assert_util.h" #include "mongo/util/concurrency/thread_pool.h" #include "mongo/util/exit.h" @@ -779,7 +778,7 @@ void ReplicationCoordinatorExternalStateImpl::_shardingOnTransitionToPrimaryHook } } - SessionCatalog::get(_service)->onStepUp(opCtx); + MongoDSessionCatalog::onStepUp(opCtx); notifyFreeMonitoringOnTransitionToPrimary(); } diff --git a/src/mongo/db/repl/replication_recovery_test.cpp b/src/mongo/db/repl/replication_recovery_test.cpp index 25786d9c151..d07d9d977ac 100644 --- a/src/mongo/db/repl/replication_recovery_test.cpp +++ b/src/mongo/db/repl/replication_recovery_test.cpp @@ -26,8 +26,6 @@ * it in the license file. */ -#include "mongo/db/repl/replication_recovery.h" - #include "mongo/platform/basic.h" #include "mongo/db/client.h" @@ -38,9 +36,10 @@ #include "mongo/db/repl/oplog_interface_local.h" #include "mongo/db/repl/replication_consistency_markers_mock.h" #include "mongo/db/repl/replication_coordinator_mock.h" +#include "mongo/db/repl/replication_recovery.h" #include "mongo/db/repl/storage_interface_impl.h" #include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/session_txn_record_gen.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/death_test.h" @@ -147,7 +146,7 @@ private: ASSERT_OK(_storageInterface->createCollection( getOperationContext(), testNs, generateOptionsWithUuid())); - SessionCatalog::get(_opCtx->getServiceContext())->onStepUp(_opCtx.get()); + MongoDSessionCatalog::onStepUp(_opCtx.get()); } void tearDown() override { diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 19eeda570b0..7c1e069fb5f 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -38,7 +38,6 @@ #include "mongo/bson/bsonelement_comparator.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/db/auth/authorization_manager.h" -#include "mongo/db/auth/authorization_manager_global.h" #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/database_holder.h" #include "mongo/db/catalog/document_validation.h" @@ -70,7 +69,8 @@ #include "mongo/db/repl/rollback_source.h" #include "mongo/db/repl/rslog.h" #include "mongo/db/s/shard_identity_rollback_notifier.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" +#include "mongo/db/transaction_participant.h" #include "mongo/util/exit.h" #include "mongo/util/fail_point_service.h" #include "mongo/util/log.h" @@ -892,7 +892,7 @@ Status _syncRollback(OperationContext* opCtx, // Find the UUID of the transactions collection. An OperationContext is required because the // UUID is not known at compile time, so the SessionCatalog needs to load the collection. - how.transactionTableUUID = SessionCatalog::getTransactionTableUUID(opCtx); + how.transactionTableUUID = MongoDSessionCatalog::getTransactionTableUUID(opCtx); log() << "Finding the Common Point"; try { @@ -1425,7 +1425,7 @@ void rollback_internal::syncFixUp(OperationContext* opCtx, oplogCollection->cappedTruncateAfter(opCtx, fixUpInfo.commonPointOurDiskloc, false); } - Status status = getGlobalAuthorizationManager()->initialize(opCtx); + Status status = AuthorizationManager::get(opCtx->getServiceContext())->initialize(opCtx); if (!status.isOK()) { severe() << "Failed to reinitialize auth data after rollback: " << redact(status); fassertFailedNoTrace(40496); diff --git a/src/mongo/db/repl/sync_tail_test.cpp b/src/mongo/db/repl/sync_tail_test.cpp index d51babb0075..095fa7b6e79 100644 --- a/src/mongo/db/repl/sync_tail_test.cpp +++ b/src/mongo/db/repl/sync_tail_test.cpp @@ -60,9 +60,8 @@ #include "mongo/db/repl/replication_process.h" #include "mongo/db/repl/storage_interface.h" #include "mongo/db/repl/sync_tail.h" -#include "mongo/db/service_context.h" #include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/session_txn_record_gen.h" #include "mongo/stdx/mutex.h" #include "mongo/unittest/death_test.h" @@ -1562,7 +1561,7 @@ public: void setUp() override { SyncTailTest::setUp(); - SessionCatalog::get(_opCtx->getServiceContext())->onStepUp(_opCtx.get()); + MongoDSessionCatalog::onStepUp(_opCtx.get()); DBDirectClient client(_opCtx.get()); BSONObj result; 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 576290f1ca4..645ae280c2e 100644 --- a/src/mongo/db/s/session_catalog_migration_destination_test.cpp +++ b/src/mongo/db/s/session_catalog_migration_destination_test.cpp @@ -44,6 +44,7 @@ #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" #include "mongo/db/transaction_participant.h" @@ -131,7 +132,7 @@ public: ->setFindHostReturnValue(kDonorConnStr.getServers()[0]); } - SessionCatalog::get(getServiceContext())->onStepUp(operationContext()); + MongoDSessionCatalog::onStepUp(operationContext()); LogicalSessionCache::set(getServiceContext(), stdx::make_unique<LogicalSessionCacheNoop>()); } diff --git a/src/mongo/db/session_catalog.cpp b/src/mongo/db/session_catalog.cpp index 5d18e890666..9f9587e1d7f 100644 --- a/src/mongo/db/session_catalog.cpp +++ b/src/mongo/db/session_catalog.cpp @@ -32,11 +32,7 @@ #include "mongo/db/session_catalog.h" -#include <boost/optional.hpp> - -#include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" -#include "mongo/db/kill_sessions_common.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" @@ -77,49 +73,6 @@ SessionCatalog* SessionCatalog::get(ServiceContext* service) { return &sessionTransactionTable; } -boost::optional<UUID> SessionCatalog::getTransactionTableUUID(OperationContext* opCtx) { - AutoGetCollection autoColl(opCtx, NamespaceString::kSessionTransactionsTableNamespace, MODE_IS); - - const auto coll = autoColl.getCollection(); - if (coll == nullptr) { - return boost::none; - } - - return coll->uuid(); -} - -void SessionCatalog::onStepUp(OperationContext* opCtx) { - invalidateSessions(opCtx, boost::none); - - DBDirectClient client(opCtx); - - const size_t initialExtentSize = 0; - const bool capped = false; - const bool maxSize = 0; - - BSONObj result; - - if (client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns(), - initialExtentSize, - capped, - maxSize, - &result)) { - return; - } - - const auto status = getStatusFromCommandResult(result); - - if (status == ErrorCodes::NamespaceExists) { - return; - } - - uassertStatusOKWithContext(status, - str::stream() - << "Failed to create the " - << NamespaceString::kSessionTransactionsTableNamespace.ns() - << " collection"); -} - ScopedCheckedOutSession SessionCatalog::checkOutSession(OperationContext* opCtx) { invariant(!opCtx->lockState()->isLocked()); invariant(opCtx->getLogicalSessionId()); @@ -204,17 +157,14 @@ void SessionCatalog::invalidateSessions(OperationContext* opCtx, void SessionCatalog::scanSessions(OperationContext* opCtx, const SessionKiller::Matcher& matcher, - stdx::function<void(OperationContext*, Session*)> workerFn) { + const ScanSessionsCallbackFn& workerFn) { stdx::lock_guard<stdx::mutex> lg(_mutex); LOG(2) << "Beginning scanSessions. Scanning " << _sessions.size() << " sessions."; - for (auto it = _sessions.begin(); it != _sessions.end(); ++it) { - // TODO SERVER-33850: Rename KillAllSessionsByPattern and - // ScopedKillAllSessionsByPatternImpersonator to not refer to session kill. - if (const KillAllSessionsByPattern* pattern = matcher.match(it->first)) { - ScopedKillAllSessionsByPatternImpersonator impersonator(opCtx, *pattern); - workerFn(opCtx, &(it->second->txnState)); + for (auto& sessionEntry : _sessions) { + if (matcher.match(sessionEntry.first)) { + workerFn(opCtx, &sessionEntry.second->txnState); } } } diff --git a/src/mongo/db/session_catalog.h b/src/mongo/db/session_catalog.h index 365202ba309..330a482de5b 100644 --- a/src/mongo/db/session_catalog.h +++ b/src/mongo/db/session_catalog.h @@ -28,6 +28,8 @@ #pragma once +#include <boost/optional.hpp> + #include "mongo/base/disallow_copying.h" #include "mongo/db/logical_session_id.h" #include "mongo/db/session.h" @@ -66,32 +68,19 @@ public: static SessionCatalog* get(ServiceContext* service); /** - * Fetches the UUID of the transaction table, or an empty optional if the collection does not - * exist or has no UUID. Acquires a lock on the collection. Required for rollback via refetch. - */ - static boost::optional<UUID> getTransactionTableUUID(OperationContext* opCtx); - - /** * Resets the transaction table to an uninitialized state. * Meant only for testing. */ void reset_forTest(); /** - * Invoked when the node enters the primary state. Ensures that the transactions collection is - * created. Throws on severe exceptions due to which it is not safe to continue the step-up - * process. - */ - void onStepUp(OperationContext* opCtx); - - /** * Potentially blocking call, which uses the session information stored in the specified - * operation context and either creates a new session runtime state (if one doesn't exist) or - * "checks-out" the existing one (if it is not currently in use). + * operation context and either creates a brand new session object (if one doesn't exist) or + * "checks-out" the existing one (if it is not currently in use or marked for kill). * - * Checking out a session puts it in the 'in use' state and all subsequent calls to checkout - * will block until it is put back in the 'available' state when the returned object goes out of - * scope. + * Checking out a session puts it in the 'checked out' state and all subsequent calls to + * checkout will block until it is checked back in. This happens when the returned object goes + * out of scope. * * Throws exception on errors. */ @@ -125,9 +114,10 @@ public: * SessionCatalog. * TODO SERVER-33850: Take Matcher out of the SessionKiller namespace. */ + using ScanSessionsCallbackFn = stdx::function<void(OperationContext*, Session*)>; void scanSessions(OperationContext* opCtx, const SessionKiller::Matcher& matcher, - stdx::function<void(OperationContext*, Session*)> workerFn); + const ScanSessionsCallbackFn& workerFn); private: struct SessionRuntimeInfo { diff --git a/src/mongo/db/session_catalog_mongod.cpp b/src/mongo/db/session_catalog_mongod.cpp new file mode 100644 index 00000000000..b5c059393e7 --- /dev/null +++ b/src/mongo/db/session_catalog_mongod.cpp @@ -0,0 +1,86 @@ +/** + * Copyright (C) 2018 MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kWrite + +#include "mongo/platform/basic.h" + +#include "mongo/db/session_catalog_mongod.h" + +#include "mongo/db/catalog_raii.h" +#include "mongo/db/client.h" +#include "mongo/db/dbdirectclient.h" +#include "mongo/db/namespace_string.h" +#include "mongo/rpc/get_status_from_command_result.h" + +namespace mongo { + +void MongoDSessionCatalog::onStepUp(OperationContext* opCtx) { + SessionCatalog::get(opCtx)->invalidateSessions(opCtx, boost::none); + + const size_t initialExtentSize = 0; + const bool capped = false; + const bool maxSize = 0; + + BSONObj result; + + DBDirectClient client(opCtx); + + if (client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns(), + initialExtentSize, + capped, + maxSize, + &result)) { + return; + } + + const auto status = getStatusFromCommandResult(result); + + if (status == ErrorCodes::NamespaceExists) { + return; + } + + uassertStatusOKWithContext(status, + str::stream() + << "Failed to create the " + << NamespaceString::kSessionTransactionsTableNamespace.ns() + << " collection"); +} + +boost::optional<UUID> MongoDSessionCatalog::getTransactionTableUUID(OperationContext* opCtx) { + AutoGetCollection autoColl(opCtx, NamespaceString::kSessionTransactionsTableNamespace, MODE_IS); + + const auto coll = autoColl.getCollection(); + if (!coll) { + return boost::none; + } + + return coll->uuid(); +} + +} // namespace mongo diff --git a/src/mongo/db/session_catalog_mongod.h b/src/mongo/db/session_catalog_mongod.h new file mode 100644 index 00000000000..78e745f1633 --- /dev/null +++ b/src/mongo/db/session_catalog_mongod.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2018 MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/session_catalog.h" + +namespace mongo { + +class MongoDSessionCatalog { +public: + /** + * Invoked when the node enters the primary state. Ensures that the transactions collection is + * created. Throws on severe exceptions due to which it is not safe to continue the step-up + * process. + */ + static void onStepUp(OperationContext* opCtx); + + /** + * Fetches the UUID of the transaction table, or an empty optional if the collection does not + * exist or has no UUID. Acquires a lock on the collection. + * + * Required for rollback via refetch. + */ + static boost::optional<UUID> getTransactionTableUUID(OperationContext* opCtx); +}; + +} // namespace mongo diff --git a/src/mongo/db/session_catalog_test.cpp b/src/mongo/db/session_catalog_test.cpp index 3efb8a0dcb3..02560433abd 100644 --- a/src/mongo/db/session_catalog_test.cpp +++ b/src/mongo/db/session_catalog_test.cpp @@ -28,12 +28,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/client.h" -#include "mongo/db/concurrency/d_concurrency.h" -#include "mongo/db/operation_context.h" #include "mongo/db/repl/mock_repl_coord_server_fixture.h" -#include "mongo/db/repl/read_concern_args.h" -#include "mongo/db/service_context.h" #include "mongo/db/session_catalog.h" #include "mongo/stdx/future.h" #include "mongo/stdx/memory.h" @@ -49,13 +44,11 @@ protected: void setUp() final { MockReplCoordServerFixture::setUp(); - auto service = opCtx()->getServiceContext(); - SessionCatalog::get(service)->reset_forTest(); - SessionCatalog::get(service)->onStepUp(opCtx()); + catalog()->reset_forTest(); } SessionCatalog* catalog() { - return SessionCatalog::get(opCtx()->getServiceContext()); + return SessionCatalog::get(getServiceContext()); } }; @@ -63,8 +56,8 @@ protected: class DirectClientSetter { public: explicit DirectClientSetter(OperationContext* opCtx) - : _opCtx(opCtx), _wasInDirectClient(opCtx->getClient()->isInDirectClient()) { - opCtx->getClient()->setInDirectClient(true); + : _opCtx(opCtx), _wasInDirectClient(_opCtx->getClient()->isInDirectClient()) { + _opCtx->getClient()->setInDirectClient(true); } ~DirectClientSetter() { diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp index 6d870f6802f..1a658477cb9 100644 --- a/src/mongo/db/transaction_participant.cpp +++ b/src/mongo/db/transaction_participant.cpp @@ -36,13 +36,13 @@ #include "mongo/db/transaction_participant.h" #include "mongo/db/catalog/index_catalog.h" +#include "mongo/db/catalog_raii.h" #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/lock_state.h" #include "mongo/db/concurrency/locker.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop_failpoint_helpers.h" -#include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/op_observer.h" diff --git a/src/mongo/db/transaction_participant_retryable_writes_test.cpp b/src/mongo/db/transaction_participant_retryable_writes_test.cpp index 0836660bba1..49803aa557b 100644 --- a/src/mongo/db/transaction_participant_retryable_writes_test.cpp +++ b/src/mongo/db/transaction_participant_retryable_writes_test.cpp @@ -41,8 +41,7 @@ #include "mongo/db/server_options.h" #include "mongo/db/server_transactions_metrics.h" #include "mongo/db/service_context.h" -#include "mongo/db/session_catalog.h" -#include "mongo/db/stats/fill_locker_info.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/transaction_participant.h" #include "mongo/stdx/future.h" #include "mongo/stdx/memory.h" @@ -127,10 +126,9 @@ protected: void setUp() final { MockReplCoordServerFixture::setUp(); - auto service = opCtx()->getServiceContext(); - SessionCatalog::get(service)->reset_forTest(); - SessionCatalog::get(service)->onStepUp(opCtx()); + MongoDSessionCatalog::onStepUp(opCtx()); + const auto service = opCtx()->getServiceContext(); OpObserverRegistry* opObserverRegistry = dynamic_cast<OpObserverRegistry*>(service->getOpObserver()); auto mockObserver = stdx::make_unique<OpObserverMock>(); @@ -139,8 +137,11 @@ protected: } void tearDown() final { - MockReplCoordServerFixture::tearDown(); _opObserver = nullptr; + + SessionCatalog::get(opCtx()->getServiceContext())->reset_forTest(); + + MockReplCoordServerFixture::tearDown(); } SessionCatalog* catalog() { diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp index 20282f83b25..3753ce81cad 100644 --- a/src/mongo/db/transaction_participant_test.cpp +++ b/src/mongo/db/transaction_participant_test.cpp @@ -41,7 +41,7 @@ #include "mongo/db/repl/optime.h" #include "mongo/db/server_transactions_metrics.h" #include "mongo/db/service_context.h" -#include "mongo/db/session_catalog.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/stats/fill_locker_info.h" #include "mongo/db/transaction_participant.h" #include "mongo/stdx/future.h" @@ -176,7 +176,8 @@ protected: MockReplCoordServerFixture::setUp(); auto service = opCtx()->getServiceContext(); - SessionCatalog::get(service)->onStepUp(opCtx()); + + MongoDSessionCatalog::onStepUp(opCtx()); OpObserverRegistry* opObserverRegistry = dynamic_cast<OpObserverRegistry*>(service->getOpObserver()); diff --git a/src/mongo/dbtests/storage_timestamp_tests.cpp b/src/mongo/dbtests/storage_timestamp_tests.cpp index d5e7cc6ae06..43c766add16 100644 --- a/src/mongo/dbtests/storage_timestamp_tests.cpp +++ b/src/mongo/dbtests/storage_timestamp_tests.cpp @@ -72,6 +72,7 @@ #include "mongo/db/s/op_observer_sharding_impl.h" #include "mongo/db/service_context.h" #include "mongo/db/session.h" +#include "mongo/db/session_catalog_mongod.h" #include "mongo/db/storage/kv/kv_storage_engine.h" #include "mongo/db/transaction_participant.h" #include "mongo/dbtests/dbtests.h" @@ -2477,7 +2478,7 @@ public: auto service = _opCtx->getServiceContext(); auto sessionCatalog = SessionCatalog::get(service); sessionCatalog->reset_forTest(); - sessionCatalog->onStepUp(_opCtx); + MongoDSessionCatalog::onStepUp(_opCtx); reset(nss); UUID ui = UUID::gen(); |