723 lines
28 KiB
C++
723 lines
28 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "ob_log_trans_ctx.h" // ObLogDepParser
|
|
#include "common/ob_clock_generator.h" // ObClockGenerator
|
|
#include "ob_log_trans_task.h" // PartTransTask
|
|
#include "ob_log_trans_ctx_mgr.h" // ObLogTransCtxMgr
|
|
#include "test_log_part_mgr_mock.h" // MockObLogPartMgr
|
|
#include "ob_log_common.h" // MAX_CACHED_TRANS_CTX_COUNT
|
|
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::liboblog;
|
|
using namespace oceanbase::transaction;
|
|
|
|
class TransCtxTest : public ::testing::Test
|
|
{
|
|
public:
|
|
static const int64_t PART_TRANS_TASK_ARRAY_SIZE = 10;
|
|
typedef ObSEArray<PartTransTask *, PART_TRANS_TASK_ARRAY_SIZE> PartTransTaskArray;
|
|
|
|
public:
|
|
TransCtxTest();
|
|
virtual ~TransCtxTest();
|
|
virtual void SetUp();
|
|
virtual void TearDown();
|
|
|
|
public:
|
|
bool is_exist(const TransCtx::ReverseDepSet &reverse_dep_set, const ObTransID &trans_id) const
|
|
{
|
|
bool ret = false;
|
|
TransCtx::ReverseDepSet::const_iterator_t itor = reverse_dep_set.begin();
|
|
for (; itor != reverse_dep_set.end(); ++itor) {
|
|
if (trans_id == *itor) {
|
|
ret = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool is_exist(const TransCtx::TransIDArray dep_parsed_reverse_deps,
|
|
const ObTransID &trans_id) const
|
|
{
|
|
bool ret = false;
|
|
ObTransID trans_id_cmp;
|
|
for (int64_t index = 0; index < dep_parsed_reverse_deps.count(); index++) {
|
|
EXPECT_EQ(OB_SUCCESS, dep_parsed_reverse_deps.at(index, trans_id_cmp));
|
|
if (trans_id == trans_id_cmp) {
|
|
ret = true;
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void init_trans_ctx(const ObTransID &trans_id, TransCtx *&trans_ctx, const bool enable_create)
|
|
{
|
|
EXPECT_TRUE(NULL != trans_ctx_mgr_);
|
|
EXPECT_TRUE(OB_SUCCESS == trans_ctx_mgr_->get_trans_ctx(trans_id, trans_ctx, enable_create));
|
|
EXPECT_TRUE(NULL != trans_ctx);
|
|
EXPECT_TRUE(OB_SUCCESS == trans_ctx->set_trans_id(trans_id));
|
|
EXPECT_TRUE(OB_SUCCESS == trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_PARTICIPANT_READY));
|
|
}
|
|
|
|
IObLogPartMgr *create_part_mgr()
|
|
{
|
|
IObLogPartMgr *part_mgr = NULL;
|
|
if (NULL != (part_mgr = (MockObLogPartMgr *)ob_malloc(sizeof(MockObLogPartMgr),
|
|
ObModIds::OB_LOG_PART_INFO))) {
|
|
new(part_mgr)MockObLogPartMgr();
|
|
}
|
|
return part_mgr;
|
|
}
|
|
|
|
IObLogTransCtxMgr *create_trans_mgr()
|
|
{
|
|
ObLogTransCtxMgr *tx_mgr = NULL;
|
|
if (NULL != (tx_mgr = (ObLogTransCtxMgr *)ob_malloc(sizeof(ObLogTransCtxMgr),
|
|
ObModIds::OB_LOG_TRANS_CTX))) {
|
|
new(tx_mgr)ObLogTransCtxMgr();
|
|
if (OB_SUCCESS != tx_mgr->init(MAX_CACHED_TRANS_CTX_COUNT)) {
|
|
tx_mgr->~ObLogTransCtxMgr();
|
|
ob_free(tx_mgr);
|
|
tx_mgr = NULL;
|
|
}
|
|
}
|
|
return tx_mgr;
|
|
}
|
|
|
|
void destroy()
|
|
{
|
|
trans_ctx_.reset();
|
|
trans_id_.reset();
|
|
part_trans_task_.reset();
|
|
if (NULL != part_mgr_) {
|
|
part_mgr_->~IObLogPartMgr();
|
|
ob_free(part_mgr_);
|
|
part_mgr_ = NULL;
|
|
}
|
|
|
|
if (NULL != trans_ctx_mgr_) {
|
|
trans_ctx_mgr_->~IObLogTransCtxMgr();
|
|
ob_free(trans_ctx_mgr_);
|
|
trans_ctx_mgr_ = NULL;
|
|
}
|
|
}
|
|
|
|
void init_part_trans_task_array(PartTransTaskArray &array, const ObTransID &trans_id)
|
|
{
|
|
EXPECT_TRUE(trans_id.is_valid());
|
|
|
|
PartTransTask *part_trans_task = NULL;
|
|
for (int i = 0; i < PART_TRANS_TASK_ARRAY_SIZE; i++) {
|
|
init_part_trans_task(part_trans_task, trans_id);
|
|
EXPECT_EQ(OB_SUCCESS, array.push_back(part_trans_task));
|
|
}
|
|
}
|
|
|
|
void free_part_trans_task_array(PartTransTaskArray &array)
|
|
{
|
|
PartTransTask *part_trans_task = NULL;
|
|
for (int i = 0; i < PART_TRANS_TASK_ARRAY_SIZE; i++) {
|
|
EXPECT_EQ(OB_SUCCESS, array.at(i, part_trans_task));
|
|
free_part_trans_task(part_trans_task);
|
|
}
|
|
}
|
|
|
|
void init_part_trans_task(PartTransTask *&part_trans_task, const ObTransID &trans_id)
|
|
{
|
|
EXPECT_TRUE(trans_id.is_valid());
|
|
|
|
if (NULL != (part_trans_task = (PartTransTask *)ob_malloc(sizeof(PartTransTask),
|
|
ObModIds::OB_LOG_PART_TRANS_TASK_SMALL))) {
|
|
new(part_trans_task)PartTransTask();
|
|
part_trans_task->set_trans_id(trans_id);
|
|
part_trans_task->set_ref_cnt(0);
|
|
part_trans_task->set_pool(NULL);
|
|
}
|
|
}
|
|
|
|
void free_part_trans_task(PartTransTask *part_trans_task)
|
|
{
|
|
if (NULL != part_trans_task) {
|
|
part_trans_task->~PartTransTask();
|
|
ob_free(part_trans_task);
|
|
part_trans_task = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
TransCtx trans_ctx_;
|
|
ObTransID trans_id_;
|
|
PartTransTask part_trans_task_;
|
|
IObLogPartMgr *part_mgr_;
|
|
IObLogTransCtxMgr *trans_ctx_mgr_;
|
|
|
|
private:
|
|
// disallow copy
|
|
DISALLOW_COPY_AND_ASSIGN(TransCtxTest);
|
|
};
|
|
|
|
TransCtxTest::TransCtxTest(): trans_ctx_(),
|
|
trans_id_(),
|
|
part_trans_task_(),
|
|
part_mgr_(NULL),
|
|
trans_ctx_mgr_(NULL)
|
|
{
|
|
}
|
|
|
|
TransCtxTest::~TransCtxTest()
|
|
{
|
|
}
|
|
|
|
void TransCtxTest::SetUp()
|
|
{
|
|
const ObAddr svr(ObAddr::IPV4, "127.0.0.1", 1000);
|
|
trans_id_ = ObTransID(svr);
|
|
part_trans_task_.set_trans_id(trans_id_);
|
|
EXPECT_TRUE(NULL != (part_mgr_ = create_part_mgr()));
|
|
EXPECT_TRUE(NULL != (trans_ctx_mgr_ = create_trans_mgr()));
|
|
trans_ctx_.set_host(trans_ctx_mgr_);
|
|
}
|
|
|
|
void TransCtxTest::TearDown()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
TEST_F(TransCtxTest, prepare_failed)
|
|
{
|
|
bool stop_flag = false;
|
|
bool need_discard = false;
|
|
IObLogPartMgr *part_mgr_null = NULL;
|
|
|
|
// 1. If part mrg is null
|
|
EXPECT_EQ(OB_INVALID_ARGUMENT, trans_ctx_.prepare(part_trans_task_, part_mgr_null, stop_flag,
|
|
need_discard));
|
|
|
|
// 2. If the state is TRANS_CTX_STATE_DISCARDED, prepare returns an error
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_DISCARDED);
|
|
EXPECT_EQ(OB_INVALID_ERROR, trans_ctx_.prepare(part_trans_task_, part_mgr_, stop_flag,
|
|
need_discard));
|
|
}
|
|
|
|
TEST_F(TransCtxTest, prepare_discard)
|
|
{
|
|
bool stop_flag = false;
|
|
bool need_discard = false;
|
|
const int64_t prepare_tstamp = 1452763000;
|
|
|
|
// prepare partition key
|
|
ObPartitionKey partition_key_0;
|
|
partition_key_0.init(1000000000, 0, 3);
|
|
|
|
// Make the prepare log timestamp less than the specified timestamp
|
|
part_trans_task_.set_partition(partition_key_0);
|
|
part_trans_task_.set_timestamp(prepare_tstamp);
|
|
part_trans_task_.set_prepare_log_id(1);
|
|
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_INVALID);
|
|
|
|
// Current transaction not in service, need discard
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.prepare(part_trans_task_, part_mgr_, stop_flag, need_discard));
|
|
EXPECT_TRUE(need_discard);
|
|
}
|
|
|
|
TEST_F(TransCtxTest, prepare_success)
|
|
{
|
|
bool stop_flag = false;
|
|
bool need_discard = false;
|
|
const int64_t prepare_tstamp = 1452763900;
|
|
|
|
// prepare partition key
|
|
ObPartitionKey partition_key_0;
|
|
partition_key_0.init(1000000000, 0, 3);
|
|
ObPartitionKey partition_key_1;
|
|
partition_key_1.init(1000000000, 1, 3);
|
|
ObPartitionKey partition_key_2;
|
|
partition_key_2.init(1000000000, 2, 3);
|
|
|
|
// If the current partitioned transaction service has 2 service participants, verify that the participants are obtained correctly
|
|
// Make the prepare log timestamp greater than the specified timestamp
|
|
part_trans_task_.set_partition(partition_key_0);
|
|
part_trans_task_.set_timestamp(prepare_tstamp);
|
|
part_trans_task_.set_prepare_log_id(1);
|
|
ObPartitionLogInfo part_info_0(partition_key_0, 1, prepare_tstamp);
|
|
ObPartitionLogInfo part_info_1(partition_key_1, 1, 1452763999);
|
|
ObPartitionLogInfo part_info_2(partition_key_2, 1, 1452763000);
|
|
PartitionLogInfoArray participants;
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_0));
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_1));
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_2));
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_.set_participants(participants));
|
|
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_INVALID);
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.prepare(part_trans_task_, part_mgr_, stop_flag, need_discard));
|
|
EXPECT_FALSE(need_discard);
|
|
const TransPartInfo *valid_participants = trans_ctx_.get_participants();
|
|
int64_t valid_participant_count = trans_ctx_.get_participant_count();
|
|
int64_t participants_count = valid_participant_count;
|
|
EXPECT_EQ(2, participants_count);
|
|
for (int64_t index = 0; index < participants_count; index++) {
|
|
EXPECT_FALSE(partition_key_2 == valid_participants[index].pkey_);
|
|
}
|
|
}
|
|
|
|
TEST_F(TransCtxTest, add_participant_failed)
|
|
{
|
|
bool is_part_trans_served = true;
|
|
bool is_all_participants_ready = false;
|
|
|
|
// 1. The current state is not advanced to the PREPARE state
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_INVALID);
|
|
EXPECT_EQ(OB_STATE_NOT_MATCH, trans_ctx_.add_participant(part_trans_task_, is_part_trans_served,
|
|
is_all_participants_ready));
|
|
|
|
// 2. The current state is already ready, the current participant will not be gathered
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_PARTICIPANT_READY);
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.add_participant(part_trans_task_, is_part_trans_served,
|
|
is_all_participants_ready));
|
|
EXPECT_FALSE(is_part_trans_served);
|
|
}
|
|
|
|
TEST_F(TransCtxTest, add_participant_not_served)
|
|
{
|
|
bool stop_flag = false;
|
|
bool need_discard = false;
|
|
bool is_part_trans_served = true;
|
|
bool is_all_participants_ready = false;
|
|
const int64_t prepare_tstamp = 1452763900;
|
|
|
|
// prepare partition key
|
|
ObPartitionKey partition_key_0;
|
|
partition_key_0.init(1000000000, 0, 3);
|
|
ObPartitionKey partition_key_1;
|
|
partition_key_1.init(1000000000, 1, 3);
|
|
|
|
// Make the prepare log timestamp greater than the specified timestamp
|
|
part_trans_task_.set_partition(partition_key_0);
|
|
part_trans_task_.set_timestamp(prepare_tstamp);
|
|
part_trans_task_.set_prepare_log_id(1);
|
|
ObPartitionLogInfo part_info_0(partition_key_0, 1, prepare_tstamp);
|
|
ObPartitionLogInfo part_info_1(partition_key_1, 1, 1452763999);
|
|
PartitionLogInfoArray participants;
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_0));
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_1));
|
|
part_trans_task_.set_participants(participants);
|
|
|
|
// 先prepare一次
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_INVALID);
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.prepare(part_trans_task_, part_mgr_, stop_flag, need_discard));
|
|
EXPECT_FALSE(need_discard);
|
|
|
|
// 构造一个partition key,不在参与者列表里
|
|
PartTransTask part_trans_task_new;
|
|
part_trans_task_new.set_trans_id(trans_id_);
|
|
ObPartitionKey partition_key_new;
|
|
partition_key_new.init(1000000000, 2, 3);
|
|
part_trans_task_new.set_partition(partition_key_new);
|
|
|
|
// 当前是prepare状态 但partition不在参与者列表中
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_PREPARED);
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.add_participant(part_trans_task_new, is_part_trans_served,
|
|
is_all_participants_ready));
|
|
EXPECT_FALSE(is_part_trans_served);
|
|
EXPECT_FALSE(is_all_participants_ready);
|
|
}
|
|
|
|
TEST_F(TransCtxTest, add_participant_all_push_in_ready)
|
|
{
|
|
bool stop_flag = false;
|
|
bool need_discard = false;
|
|
bool is_part_trans_served = true;
|
|
bool is_all_participants_ready = false;
|
|
const int64_t prepare_tstamp = 1452763900;
|
|
|
|
// prepare partition key
|
|
ObPartitionKey partition_key_0;
|
|
partition_key_0.init(1000000000, 0, 3);
|
|
ObPartitionKey partition_key_1;
|
|
partition_key_1.init(1000000000, 1, 3);
|
|
|
|
// Make the prepare log timestamp greater than the specified timestamp
|
|
part_trans_task_.set_partition(partition_key_0);
|
|
part_trans_task_.set_timestamp(prepare_tstamp);
|
|
part_trans_task_.set_prepare_log_id(1);
|
|
ObPartitionLogInfo part_info_0(partition_key_0, 1, prepare_tstamp);
|
|
ObPartitionLogInfo part_info_1(partition_key_1, 1, 1452763999);
|
|
PartitionLogInfoArray participants;
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_0));
|
|
EXPECT_EQ(OB_SUCCESS, participants.push_back(part_info_1));
|
|
part_trans_task_.set_participants(participants);
|
|
|
|
// Prepare first, generating a list of participants for all services
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_INVALID);
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.prepare(part_trans_task_, part_mgr_, stop_flag, need_discard));
|
|
EXPECT_FALSE(need_discard);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PREPARED, trans_ctx_.get_state());
|
|
|
|
PartTransTask part_trans_task_2;
|
|
part_trans_task_2.set_trans_id(trans_id_);
|
|
part_trans_task_2.set_partition(partition_key_1);
|
|
part_trans_task_2.set_timestamp(prepare_tstamp + 100);
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.prepare(part_trans_task_2, part_mgr_, stop_flag, need_discard));
|
|
EXPECT_FALSE(need_discard);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PREPARED, trans_ctx_.get_state());
|
|
|
|
// 1.Currently in prepare state: partition 1 is in the participants list, then it is added to the ready list, but has not yet reached the ready state
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.add_participant(part_trans_task_, is_part_trans_served,
|
|
is_all_participants_ready));
|
|
EXPECT_TRUE(is_part_trans_served);
|
|
EXPECT_FALSE(is_all_participants_ready);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PREPARED, trans_ctx_.get_state());
|
|
|
|
// 2.All partitions have been added to the ready list and should be in the ready state
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.add_participant(part_trans_task_2, is_part_trans_served,
|
|
is_all_participants_ready));
|
|
EXPECT_TRUE(is_part_trans_served);
|
|
EXPECT_TRUE(is_all_participants_ready);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PARTICIPANT_READY, trans_ctx_.get_state());
|
|
}
|
|
|
|
TEST_F(TransCtxTest, parse_deps_failed)
|
|
{
|
|
IObLogTransCtxMgr *trans_ctx_mgr = NULL;
|
|
bool all_deps_cleared = false;
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_PREPARED);
|
|
EXPECT_EQ(OB_STATE_NOT_MATCH, trans_ctx_.parse_deps(trans_ctx_mgr, all_deps_cleared));
|
|
EXPECT_FALSE(all_deps_cleared);
|
|
|
|
trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_PARTICIPANT_READY);
|
|
EXPECT_EQ(OB_INVALID_ARGUMENT, trans_ctx_.parse_deps(trans_ctx_mgr, all_deps_cleared));
|
|
EXPECT_FALSE(all_deps_cleared);
|
|
}
|
|
|
|
TEST_F(TransCtxTest, parse_deps_and_sequence)
|
|
{
|
|
// Create 4 transactions
|
|
const ObAddr svr1(ObAddr::IPV4, "127.0.0.1", 1000);
|
|
const ObAddr svr2(ObAddr::IPV4, "127.0.0.1", 2000);
|
|
const ObAddr svr3(ObAddr::IPV4, "127.0.0.1", 3000);
|
|
const ObAddr svr4(ObAddr::IPV4, "127.0.0.1", 4000);
|
|
const ObTransID trans_id_1(svr1);
|
|
const ObTransID trans_id_2(svr2);
|
|
const ObTransID trans_id_3(svr3);
|
|
const ObTransID trans_id_4(svr4);
|
|
|
|
TransCtx *trans_ctx_1 = NULL;
|
|
TransCtx *trans_ctx_2 = NULL;
|
|
TransCtx *trans_ctx_3 = NULL;
|
|
TransCtx *trans_ctx_4 = NULL;
|
|
bool enable_create = true;
|
|
|
|
// init 4 trans_ctx
|
|
init_trans_ctx(trans_id_1, trans_ctx_1, enable_create);
|
|
init_trans_ctx(trans_id_2, trans_ctx_2, enable_create);
|
|
init_trans_ctx(trans_id_3, trans_ctx_3, enable_create);
|
|
init_trans_ctx(trans_id_4, trans_ctx_4, enable_create);
|
|
|
|
// set deps of trans
|
|
trans_ctx_1->set_deps(trans_id_2);
|
|
trans_ctx_1->set_deps(trans_id_3);
|
|
trans_ctx_2->set_deps(trans_id_3);
|
|
trans_ctx_3->set_deps(trans_id_4);
|
|
|
|
bool all_deps_cleared = false;
|
|
TransCtx::TransIDArray dep_parsed_reverse_deps;
|
|
|
|
// 1. trans_ctx 4 can be ordered
|
|
// trans_ctx_4 parses the dependencies (since there are no dependencies, the partitioned transaction parses the end of the dependencies and the state is changed from ready->parsed)
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_4->parse_deps(trans_ctx_mgr_, all_deps_cleared));
|
|
EXPECT_TRUE(all_deps_cleared);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_DEP_PARSED, trans_ctx_4->get_state());
|
|
|
|
// trans_ctx_4 sequenced
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_4->sequence(0, 0));
|
|
|
|
// trans_ctx_4 parse reverse deps
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_4->parse_reverse_deps(trans_ctx_mgr_, dep_parsed_reverse_deps));
|
|
EXPECT_EQ(0, dep_parsed_reverse_deps.count());
|
|
|
|
// 2. trans_ctx 1 cannot be ordered
|
|
// trans_ctx_1 analyses the dependencies and adds the reverse dependency list of 2 and 3, with the status ready, because 2 and 3 are not ordered
|
|
all_deps_cleared = false;
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_1->parse_deps(trans_ctx_mgr_, all_deps_cleared));
|
|
EXPECT_FALSE(all_deps_cleared);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PARTICIPANT_READY, trans_ctx_1->get_state());
|
|
// Determine if the reverse dependency list for the next 2/3 includes 1
|
|
const TransCtx::ReverseDepSet &reverse_dep_set_2 = trans_ctx_2->get_reverse_dep_set();
|
|
EXPECT_EQ(1, reverse_dep_set_2.count());
|
|
EXPECT_TRUE(is_exist(reverse_dep_set_2, trans_id_1));
|
|
const TransCtx::ReverseDepSet &reverse_dep_set_3 = trans_ctx_3->get_reverse_dep_set();
|
|
EXPECT_EQ(1, reverse_dep_set_3.count());
|
|
EXPECT_TRUE(is_exist(reverse_dep_set_3, trans_id_1));
|
|
|
|
// 3.trans_ctx 2 cannot be ordered and will join the set of reverse dependencies of 3
|
|
all_deps_cleared = false;
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_2->parse_deps(trans_ctx_mgr_, all_deps_cleared));
|
|
EXPECT_FALSE(all_deps_cleared);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PARTICIPANT_READY, trans_ctx_2->get_state());
|
|
// Determine the reverse dependency list for 3, containing 2
|
|
const TransCtx::ReverseDepSet &reverse_dep_set_3_new = trans_ctx_3->get_reverse_dep_set();
|
|
EXPECT_EQ(2, reverse_dep_set_3_new.count());
|
|
EXPECT_TRUE(is_exist(reverse_dep_set_3_new, trans_id_2));
|
|
|
|
// 4.trans-ctx 3 can parse deps
|
|
all_deps_cleared = false;
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_3->parse_deps(trans_ctx_mgr_, all_deps_cleared));
|
|
EXPECT_TRUE(all_deps_cleared);
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_DEP_PARSED, trans_ctx_3->get_state());
|
|
|
|
// trans_ctx_3 sequenced
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_3->sequence(1, 1));
|
|
|
|
// trans_ctx_3 parse reverse deps
|
|
dep_parsed_reverse_deps.reset();
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_3->parse_reverse_deps(trans_ctx_mgr_, dep_parsed_reverse_deps));
|
|
EXPECT_EQ(1, dep_parsed_reverse_deps.count());
|
|
EXPECT_TRUE(is_exist(dep_parsed_reverse_deps, trans_id_2));
|
|
|
|
// The set of dependencies of trans 2 is 0 and the set of dependencies of trans 1 is 1
|
|
EXPECT_EQ(0, trans_ctx_2->get_cur_dep_count());
|
|
EXPECT_EQ(1, trans_ctx_1->get_cur_dep_count());
|
|
|
|
// 2 Execution of sequencing, reverse decoupling
|
|
dep_parsed_reverse_deps.reset();
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_2->sequence(2, 2));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_2->parse_reverse_deps(trans_ctx_mgr_, dep_parsed_reverse_deps));
|
|
EXPECT_EQ(1, dep_parsed_reverse_deps.count());
|
|
EXPECT_EQ(0, trans_ctx_1->get_cur_dep_count());
|
|
EXPECT_TRUE(is_exist(dep_parsed_reverse_deps, trans_id_1));
|
|
|
|
// 5.trans_ctx_1 can be sequenced
|
|
dep_parsed_reverse_deps.reset();
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_1->sequence(3, 3));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_1->parse_reverse_deps(trans_ctx_mgr_, dep_parsed_reverse_deps));
|
|
EXPECT_EQ(0, dep_parsed_reverse_deps.count());
|
|
}
|
|
|
|
TEST_F(TransCtxTest, format_participant_failed)
|
|
{
|
|
TransCtx *trans_ctx = NULL;
|
|
bool enable_create = true;
|
|
init_trans_ctx(trans_id_, trans_ctx, enable_create);
|
|
|
|
// 1.Transaction status not in order, error reported
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_DEP_PARSED));
|
|
EXPECT_EQ(OB_STATE_NOT_MATCH, trans_ctx->format_participant(part_trans_task_));
|
|
|
|
// 2.Inconsistent transaction id, error reported
|
|
const ObAddr svr(ObAddr::IPV4, "127.0.0.1", 2000);
|
|
const ObTransID trans_id(svr);
|
|
PartTransTask part_trans_task;
|
|
part_trans_task.set_trans_id(trans_id);
|
|
|
|
EXPECT_EQ(OB_INVALID_ARGUMENT, trans_ctx->format_participant(part_trans_task));
|
|
}
|
|
|
|
TEST_F(TransCtxTest, format_participant)
|
|
{
|
|
TransCtx *trans_ctx = NULL;
|
|
bool enable_create = true;
|
|
init_trans_ctx(trans_id_, trans_ctx, enable_create);
|
|
|
|
// Total of 10 partition transactions
|
|
PartTransTaskArray part_trans_task_array;
|
|
init_part_trans_task_array(part_trans_task_array, trans_id_);
|
|
EXPECT_TRUE(PART_TRANS_TASK_ARRAY_SIZE == part_trans_task_array.count());
|
|
|
|
// Set the number of ready participants
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_count(PART_TRANS_TASK_ARRAY_SIZE));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_SEQUENCED));
|
|
|
|
// After the first 9 formations, each time the transaction status is not updated, the formated participant count is increased by 1
|
|
int64_t formated_count = 0;
|
|
PartTransTask *part_trans_task = NULL;
|
|
int64_t index = 0;
|
|
for (index = 0; index < PART_TRANS_TASK_ARRAY_SIZE - 1; index++) {
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_array.at(index, part_trans_task));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->format_participant(*part_trans_task));
|
|
EXPECT_EQ(++formated_count, trans_ctx->get_formatted_participant_count());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_SEQUENCED, trans_ctx->get_state());
|
|
}
|
|
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_array.at(index, part_trans_task));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->format_participant(*part_trans_task));
|
|
EXPECT_EQ(trans_ctx->get_ready_participant_count(), trans_ctx->get_formatted_participant_count());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_FORMATTED, trans_ctx->get_state());
|
|
|
|
free_part_trans_task_array(part_trans_task_array);
|
|
part_trans_task_array.destroy();
|
|
}
|
|
|
|
TEST_F(TransCtxTest, commit)
|
|
{
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_SEQUENCED));
|
|
EXPECT_EQ(OB_STATE_NOT_MATCH, trans_ctx_.commit());
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.set_state(TransCtx::TRANS_CTX_STATE_FORMATTED));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx_.commit());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_COMMITTED, trans_ctx_.get_state());
|
|
}
|
|
|
|
TEST_F(TransCtxTest, release_participants_failed)
|
|
{
|
|
TransCtx *trans_ctx = NULL;
|
|
bool enable_create = true;
|
|
init_trans_ctx(trans_id_, trans_ctx, enable_create);
|
|
|
|
// 1. The current state is not a commit state and an error is reported
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_SEQUENCED));
|
|
EXPECT_EQ(OB_STATE_NOT_MATCH, trans_ctx->release_participants());
|
|
|
|
// 2. Not all parts are currently available for release, 10 partitioned transactions in total
|
|
PartTransTaskArray part_trans_task_array;
|
|
init_part_trans_task_array(part_trans_task_array, trans_id_);
|
|
EXPECT_TRUE(PART_TRANS_TASK_ARRAY_SIZE == part_trans_task_array.count());
|
|
|
|
// Set the number of ready participants, the status is commited
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_count(PART_TRANS_TASK_ARRAY_SIZE));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_COMMITTED));
|
|
|
|
// set next participant
|
|
PartTransTask *part_trans_task = NULL;
|
|
PartTransTask *first_part_trans_task = NULL;
|
|
PartTransTask *next_part_trans_task = NULL;
|
|
int64_t index = 0;
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_array.at(0, part_trans_task));
|
|
first_part_trans_task = part_trans_task;
|
|
|
|
for (index = 0; index < PART_TRANS_TASK_ARRAY_SIZE - 1; index++) {
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_array.at(index + 1, next_part_trans_task));
|
|
part_trans_task->set_next_participant(next_part_trans_task);
|
|
part_trans_task = next_part_trans_task;
|
|
}
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_objs(first_part_trans_task));
|
|
bool all_part_releasable = false;
|
|
for (index = 0; index < PART_TRANS_TASK_ARRAY_SIZE - 1; index++) {
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->inc_releasable_participant_count(all_part_releasable));
|
|
}
|
|
|
|
// Not all parts are releasable, error reported
|
|
EXPECT_EQ(OB_STATE_NOT_MATCH, trans_ctx->release_participants());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_COMMITTED, trans_ctx->get_state());
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->inc_releasable_participant_count(all_part_releasable));
|
|
EXPECT_TRUE(true == all_part_releasable);
|
|
|
|
// 3. Not all part reference counts are 0, error reported
|
|
part_trans_task->set_ref_cnt(2);
|
|
next_part_trans_task->set_ref_cnt(1);
|
|
EXPECT_EQ(OB_ERR_UNEXPECTED, trans_ctx->release_participants());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_COMMITTED, trans_ctx->get_state());
|
|
|
|
free_part_trans_task_array(part_trans_task_array);
|
|
part_trans_task_array.destroy();
|
|
}
|
|
|
|
TEST_F(TransCtxTest, releasd_participants_less_than_ready)
|
|
{
|
|
TransCtx *trans_ctx = NULL;
|
|
bool enable_create = true;
|
|
init_trans_ctx(trans_id_, trans_ctx, enable_create);
|
|
|
|
PartTransTask *part_trans_task;
|
|
init_part_trans_task(part_trans_task, trans_id_);
|
|
|
|
// set count of ready participants, status is commited
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_count(PART_TRANS_TASK_ARRAY_SIZE));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_COMMITTED));
|
|
|
|
// set next participant
|
|
part_trans_task->set_next_participant(NULL);
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_objs(part_trans_task));
|
|
EXPECT_TRUE(NULL != trans_ctx->get_participant_objs());
|
|
bool all_part_releasable = false;
|
|
for (int index = 0; index < PART_TRANS_TASK_ARRAY_SIZE; index++) {
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->inc_releasable_participant_count(all_part_releasable));
|
|
}
|
|
|
|
EXPECT_TRUE(true == all_part_releasable);
|
|
EXPECT_EQ(OB_INVALID_ERROR, trans_ctx->release_participants());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_COMMITTED, trans_ctx->get_state());
|
|
|
|
free_part_trans_task(part_trans_task);
|
|
}
|
|
|
|
TEST_F(TransCtxTest, release_participants)
|
|
{
|
|
TransCtx *trans_ctx = NULL;
|
|
bool enable_create = true;
|
|
init_trans_ctx(trans_id_, trans_ctx, enable_create);
|
|
|
|
// Total of 10 partition transactions
|
|
PartTransTaskArray part_trans_task_array;
|
|
init_part_trans_task_array(part_trans_task_array, trans_id_);
|
|
EXPECT_TRUE(PART_TRANS_TASK_ARRAY_SIZE == part_trans_task_array.count());
|
|
|
|
// set count of ready participants, status is commited
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_count(PART_TRANS_TASK_ARRAY_SIZE));
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_state(TransCtx::TRANS_CTX_STATE_COMMITTED));
|
|
|
|
// set ready participant objs
|
|
PartTransTask *part_trans_task = NULL;
|
|
PartTransTask *first_part_trans_task = NULL;
|
|
PartTransTask *next_part_trans_task = NULL;
|
|
int64_t index = 0;
|
|
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_array.at(0, part_trans_task));
|
|
first_part_trans_task = part_trans_task;
|
|
for (index = 0; index < PART_TRANS_TASK_ARRAY_SIZE - 1; index++) {
|
|
EXPECT_EQ(OB_SUCCESS, part_trans_task_array.at(index + 1, next_part_trans_task));
|
|
part_trans_task->set_next_participant(next_part_trans_task);
|
|
part_trans_task = next_part_trans_task;
|
|
}
|
|
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->set_ready_participant_objs(first_part_trans_task));
|
|
EXPECT_TRUE(NULL != trans_ctx->get_participant_objs());
|
|
|
|
bool all_part_releasable = false;
|
|
for (index = 0; index < PART_TRANS_TASK_ARRAY_SIZE; index++) {
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->inc_releasable_participant_count(all_part_releasable));
|
|
}
|
|
|
|
EXPECT_TRUE(true == all_part_releasable);
|
|
EXPECT_EQ(OB_SUCCESS, trans_ctx->release_participants());
|
|
EXPECT_EQ(TransCtx::TRANS_CTX_STATE_PARTICIPANT_RELEASED, trans_ctx->get_state());
|
|
EXPECT_TRUE(0 == trans_ctx->get_ready_participant_count());
|
|
EXPECT_TRUE(0 == trans_ctx->get_releasable_participant_count());
|
|
EXPECT_TRUE(0 == trans_ctx->get_formatted_participant_count());
|
|
EXPECT_TRUE(NULL == trans_ctx->get_participant_objs());
|
|
|
|
free_part_trans_task_array(part_trans_task_array);
|
|
part_trans_task_array.destroy();
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
// used for init of ObTransIDTest for incoming length errors
|
|
ObClockGenerator::init();
|
|
|
|
OB_LOGGER.set_log_level("INFO");
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|