Files
oceanbase/unittest/liboblog/test_log_trans_ctx.cpp
2021-09-30 19:50:25 +08:00

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();
}