| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #pragma once |
| |
| #include <atomic> |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| |
| #include <gtest/gtest_prod.h> |
| |
| #include "kudu/gutil/macros.h" |
| #include "kudu/util/status.h" |
| |
| namespace kudu { |
| class MonoTime; |
| |
| namespace master { |
| class Master; |
| } |
| |
| namespace transactions { |
| |
| class TxnStatusEntryPB; |
| class TxnSystemClient; |
| |
| // This class encapsulates the logic used by the TxnManagerService while serving |
| // RPC requests (see txn_manager.proto for the protobuf interface). The most |
| // essential piece of the logic implemented by this class is the assignment of |
| // an identifier for a new transaction. All other methods simply do proxying |
| // of corresponding requests to the underlying instance of TxnSystemClient |
| // aggregated by this class. |
| class TxnManager final { |
| public: |
| explicit TxnManager(master::Master* server); |
| ~TxnManager(); |
| |
| // Use next transaction identifier and call BeginTransaction() via |
| // txn_sys_client_, adjusting the highest seen txn_id. |
| Status BeginTransaction(const std::string& username, |
| const MonoTime& deadline, |
| int64_t* txn_id, |
| uint32_t* txn_keepalive_ms); |
| |
| // Initiate the commit phase for the transaction. The control is returned |
| // right after initiating the commit phase: the caller can check for the |
| // completion of the commit phase using the GetTransactionState() RPC. |
| // So, in some sense this is an asynchronous method. |
| Status CommitTransaction(int64_t txn_id, |
| const std::string& username, |
| const MonoTime& deadline); |
| |
| // The three method below proxy calls to the underlying txn_sys_client_. |
| Status AbortTransaction(int64_t txn_id, |
| const std::string& username, |
| const MonoTime& deadline); |
| |
| Status GetTransactionState(int64_t txn_id, |
| const std::string& username, |
| const MonoTime& deadline, |
| TxnStatusEntryPB* txn_status); |
| |
| Status KeepTransactionAlive(int64_t txn_id, |
| const std::string& username, |
| const MonoTime& deadline); |
| |
| private: |
| friend class master::Master; |
| FRIEND_TEST(TxnManagerTest, LazyInitialization); |
| FRIEND_TEST(TxnManagerTest, NonlazyInitialization); |
| FRIEND_TEST(TxnManagerTest, LazyInitializationConcurrentCalls); |
| |
| // Initialize the internals: create transaction status table (if not exists), |
| // create and initialize txn_sys_client_, etc. This method should not be |
| // called concurrently or multiple times. |
| Status Init(); |
| |
| // Return Status::OK() if TxnManager is initialized, otherwise return |
| // Status::ServiceUnavailable() unless TxnManager is configured to initialize |
| // lazily. If the latter, schedule the initialization via master's thread |
| // pool and wait for that to be completed no later than prescribed |
| // by the 'deadline' parameter. A non-initialized instance of MonoTime |
| // passed as the 'deadline' parameter has a special meaning: wait indefinitely |
| // for the initialization of the TxnManager. |
| Status CheckInitialized(const MonoTime& deadline); |
| |
| // Whether or not this instance is lazily initialized. |
| const bool is_lazily_initialized_; |
| |
| // The span of a range partition to use when adding new ranges to the |
| // transaction status table. |
| const int64_t txn_status_table_range_span_; |
| |
| // The pointer to the top-level Master object. From the lifecycle perspective, |
| // Master is assumed to be alive during the whole lifecycle of TxnManager |
| // since the Master is the component that hosts TxnManager (this is similar |
| // to the relations between the CatalogManager and the Master). |
| master::Master* server_; |
| |
| // TxnSystemClient instance to communicate with TxnStatusManager. |
| std::unique_ptr<TxnSystemClient> txn_sys_client_; |
| |
| // Whether it's necessary to schedule the initialization of this TxnManager |
| // instance (this is relavant only in case of lazily initialized instance). |
| std::atomic<bool> need_init_; |
| |
| // Whether this object is initialized. In case of lazily initialized instance, |
| // the approach with atomics performs better compared with the approach using |
| // the 'standard' synchronization primitives. |
| std::atomic<bool> initialized_; |
| |
| // The next_txn_id_ is used as a hint for next transaction identifier to try |
| // when assigning an identifier to a new transaction. |
| std::atomic<int64_t> next_txn_id_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TxnManager); |
| }; |
| |
| } // namespace transactions |
| } // namespace kudu |