/** * 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 #include #include "mongo/base/disallow_copying.h" #include "mongo/db/s/transaction_coordinator.h" #include "mongo/stdx/condition_variable.h" #include "mongo/util/concurrency/with_lock.h" namespace mongo { /** * A container for TransactionCoordinator objects, indexed by logical session id and transaction * number. It allows holding several coordinator objects per session. It also knows how to recreate * itself from the config.txnCommitDecisions collection, which will be done on transition to * primary (whether from startup or ordinary step up). */ class TransactionCoordinatorCatalog { MONGO_DISALLOW_COPYING(TransactionCoordinatorCatalog); public: TransactionCoordinatorCatalog(); ~TransactionCoordinatorCatalog(); /** * Inserts a coordinator into the catalog. * * Note: Inserting a duplicate coordinator for the given session id and transaction number * is not allowed and will lead to an invariant failure. Users of the catalog must ensure this * does not take place. */ void insert(OperationContext* opCtx, LogicalSessionId lsid, TxnNumber txnNumber, std::shared_ptr coordinator, bool forStepUp = false); /** * Returns the coordinator with the given session id and transaction number, if it exists. If it * does not exist, return nullptr. */ std::shared_ptr get(OperationContext* opCtx, LogicalSessionId lsid, TxnNumber txnNumber); /** * Returns the coordinator with the highest transaction number with the given session id, if it * exists. If it does not exist, return boost::none. */ boost::optional>> getLatestOnSession(OperationContext* opCtx, LogicalSessionId lsid); /** * Removes the coordinator with the given session id and transaction number from the catalog, if * one exists, and if this the last coordinator in the catalog, signals that there are no active * coordinators. * * Note: The coordinator must be in a state suitable for removal (i.e. committed or aborted). */ void remove(LogicalSessionId lsid, TxnNumber txnNumber); /** * Marks no stepup in progress and signals that no stepup is in progress. */ void exitStepUp(Status status); /** * Blocking method, which waits for all coordinators registered on the catalog to complete * (after this returns, it is guaranteed that all onCompletion futures have been set) */ void join(); /** * Returns a string representation of the map from LogicalSessionId to the list of TxnNumbers * with TransactionCoordinators currently in the catalog. */ std::string toString() const; private: // Map of transaction coordinators, ordered in decreasing transaction number with the most // recent transaction at the front using TransactionCoordinatorMap = std::map, std::greater>; /** * Blocks in an interruptible wait until the catalog is not marked as having a stepup in * progress. */ void _waitForStepUpToComplete(stdx::unique_lock& lk, OperationContext* opCtx); /** * Constructs a string representation of all the coordinators registered on the catalog. */ std::string _toString(WithLock wl) const; // Protects the state below. mutable stdx::mutex _mutex; // Contains TransactionCoordinator objects by session id and transaction number. May contain // more than one coordinator per session. All coordinators for a session that do not correspond // to the latest transaction should either be in the process of committing or aborting. LogicalSessionIdMap _coordinatorsBySession; // Used only for testing. Contains TransactionCoordinator objects which have completed their // commit coordination and would normally be expunged from memory. LogicalSessionIdMap _coordinatorsBySessionDefunct; // Stores the result of the coordinator catalog's recovery attempt (the status passed to // exitStepUp). This is what the values mean: // // stepUpCompletionStatus = none - brand new created object (exitStepUp has not been called // yet). All calls will block. // stepUpCompletionStatus = OK - recovery completed successfully, transactions can be // coordinated // stepUpCompletionStatus = error - recovery completed with an error, transactions cannot be // coordinated (all methods will fail with this error) boost::optional _stepUpCompletionStatus; // Signaled when recovery of the catalog completes (when _stepUpCompletionStatus transitions // from none to either OK or error) stdx::condition_variable _stepUpCompleteCv; // Notified when the last coordinator is removed from the catalog. stdx::condition_variable _noActiveCoordinatorsCv; }; } // namespace mongo