blob: 01bd082b19756f4328f5192ed6d3cad2929a61f1 [file] [log] [blame]
// 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