463 lines
23 KiB
C++
463 lines
23 KiB
C++
// Copyright (c) 2021 OceanBase
|
|
// OceanBase 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 "lib/file/file_directory_utils.h"
|
|
#include "lib/utility/ob_macro_utils.h"
|
|
#include "logservice/palf/log_define.h"
|
|
#include <cstdio>
|
|
#include <gtest/gtest.h>
|
|
#include <signal.h>
|
|
#include "lib/utility/ob_defer.h"
|
|
#define private public
|
|
#include "env/ob_simple_log_cluster_env.h"
|
|
|
|
#undef private
|
|
|
|
const std::string TEST_NAME = "flashback";
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase;
|
|
namespace oceanbase
|
|
{
|
|
using namespace logservice;
|
|
|
|
namespace logservice
|
|
{
|
|
int LogRequestHandler::change_access_mode_(const LogChangeAccessModeCmd &req)
|
|
{
|
|
int ret = common::OB_SUCCESS;
|
|
if (false == req.is_valid()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
CLOG_LOG(ERROR, "Invalid argument!!!", K(ret), K(req));
|
|
} else {
|
|
palf::PalfHandleGuard palf_handle_guard;
|
|
const int64_t palf_id = req.ls_id_;
|
|
const common::ObAddr &server = req.src_;
|
|
int64_t proposal_id = palf::INVALID_PROPOSAL_ID;
|
|
common::ObRole role = ObRole::FOLLOWER;
|
|
if (OB_FAIL(get_palf_handle_guard_(palf_id, palf_handle_guard))) {
|
|
CLOG_LOG(WARN, "get_palf_handle_guard_ failed", K(ret), K(palf_id));
|
|
} else if (OB_FAIL(palf_handle_guard.get_role(role, proposal_id))) {
|
|
} else if (OB_FAIL(palf_handle_guard.change_access_mode(proposal_id, req.mode_version_,
|
|
req.access_mode_, req.ref_scn_))) {
|
|
CLOG_LOG(WARN, "change_access_mode failed", K(ret), K(palf_id), K(server));
|
|
} else {
|
|
CLOG_LOG(INFO, "change_access_mode success", K(ret), K(req));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogFlashbackService::get_ls_list_(const uint64_t tenant_id,
|
|
share::ObLSStatusInfoArray &ls_array)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
common::ObFunction<int(const palf::PalfHandle&)> get_palf_info =
|
|
[&](const palf::PalfHandle &palf_handle)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
share::ObLSStatusInfo ls_status;
|
|
int64_t palf_id = -1;
|
|
palf_handle.get_palf_id(palf_id);
|
|
share::ObLSFlag flag(share::ObLSFlag::NORMAL_FLAG);
|
|
if (OB_FAIL(ls_status.init(tenant_id, share::ObLSID(palf_id), 1, share::ObLSStatus::OB_LS_NORMAL, 1, "z1", flag))) {
|
|
CLOG_LOG(WARN, "ls_status init failed", K(ret), K(palf_id));
|
|
} else if (OB_FAIL(ls_array.push_back(ls_status))) {
|
|
CLOG_LOG(WARN, "ls_array push_back failed", K(ret), K(palf_id));
|
|
}
|
|
return ret;
|
|
};
|
|
logservice::ObLogService *log_service = NULL;
|
|
log_service = MTL(logservice::ObLogService*);
|
|
if (false == get_palf_info.is_valid()) {
|
|
CLOG_LOG(ERROR, "invalid ObFunction", K(ret));
|
|
} else if (OB_FAIL(log_service->iterate_palf(get_palf_info))) {
|
|
CLOG_LOG(ERROR, "iterate_palf failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogFlashbackService::BaseLSOperator::update_leader_()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
leader_.reset();
|
|
logservice::ObLogService *log_service = NULL;
|
|
log_service = MTL(logservice::ObLogService*);
|
|
palf::PalfHandleGuard palf_handle;
|
|
if (OB_FAIL(log_service->open_palf(ls_id_, palf_handle))) {
|
|
CLOG_LOG(ERROR, "open_palf failed", K(ret), K_(ls_id));
|
|
} else {
|
|
palf::PalfHandleImpl *palf_handle_impl = dynamic_cast<palf::PalfHandleImpl*>(palf_handle.palf_handle_.palf_handle_impl_);
|
|
leader_ = palf_handle_impl->state_mgr_.get_leader();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int LogRequestHandler::get_self_addr_(common::ObAddr &self) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
logservice::ObLogService *log_service = NULL;
|
|
log_service = MTL(logservice::ObLogService*);
|
|
self = log_service->self_;
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
|
|
namespace unittest
|
|
{
|
|
class TestObSimpleLogClusterFlashback : public ObSimpleLogClusterTestEnv
|
|
{
|
|
public:
|
|
TestObSimpleLogClusterFlashback() {}
|
|
};
|
|
|
|
int64_t ObSimpleLogClusterTestBase::member_cnt_ = 1;
|
|
int64_t ObSimpleLogClusterTestBase::node_cnt_ = 5;
|
|
std::string ObSimpleLogClusterTestBase::test_name_ = TEST_NAME;
|
|
bool ObSimpleLogClusterTestBase::need_add_arb_server_ = false;
|
|
|
|
|
|
// test cases:
|
|
// 1. basic multiple replica flashback
|
|
// 2. some replicas has been flashbacked and reconfirm
|
|
TEST_F(TestObSimpleLogClusterFlashback, flashback_basic_func)
|
|
{
|
|
SET_CASE_LOG_FILE(TEST_NAME, "flashback_basic_func");
|
|
OB_LOGGER.set_log_level("INFO");
|
|
// 2 log streams
|
|
// log stream 1's end_ts_ns is higher than flashback_ts
|
|
// log stream 2's end_ts_ns is less than flashback_ts
|
|
|
|
const int64_t id1 = ATOMIC_AAF(&palf_id_, 1);
|
|
const int64_t id2 = ATOMIC_AAF(&palf_id_, 1);
|
|
const int64_t CONFIG_CHANGE_TIMEOUT_US = 10 * 1000L * 1000L;
|
|
int64_t leader_idx1 = 0, leader_idx2 = 0;
|
|
int64_t mode_version1 = INVALID_PROPOSAL_ID, mode_version2 = INVALID_PROPOSAL_ID;
|
|
ObLogFlashbackService *flashback_srv = NULL;
|
|
// 1. create 2 palfs, each palf with 3 replicas
|
|
unittest::PalfHandleImplGuard leader1, leader2;
|
|
EXPECT_EQ(OB_SUCCESS, create_paxos_group(id1, leader_idx1, leader1));
|
|
EXPECT_EQ(OB_SUCCESS, create_paxos_group(id2, leader_idx2, leader2));
|
|
LogConfigVersion config_version;
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_config_version(config_version));
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_member(ObMember(get_cluster()[1]->get_addr(), 1), 2, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_member(ObMember(get_cluster()[2]->get_addr(), 1), 3, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_learner(ObMember(get_cluster()[3]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_learner(ObMember(get_cluster()[4]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
ASSERT_EQ(OB_SUCCESS, leader2.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader2.palf_handle_impl_->add_member(ObMember(get_cluster()[1]->get_addr(), 1), 2, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
ASSERT_EQ(OB_SUCCESS, leader2.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader2.palf_handle_impl_->add_member(ObMember(get_cluster()[2]->get_addr(), 1), 3, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader2.palf_handle_impl_->add_learner(ObMember(get_cluster()[3]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader2.palf_handle_impl_->add_learner(ObMember(get_cluster()[4]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, submit_log(leader1, 500, leader_idx1));
|
|
EXPECT_EQ(OB_SUCCESS, submit_log(leader2, 500, leader_idx2));
|
|
SCN flashback_scn;
|
|
flashback_scn.convert_from_ts(common::ObTimeUtility::current_time());
|
|
EXPECT_EQ(OB_SUCCESS, submit_log(leader1, 500, leader_idx1));
|
|
wait_until_has_committed(leader1, leader1.palf_handle_impl_->get_max_lsn());
|
|
wait_until_has_committed(leader2, leader2.palf_handle_impl_->get_max_lsn());
|
|
EXPECT_GT(flashback_scn, leader2.palf_handle_impl_->get_max_scn());
|
|
EXPECT_LT(flashback_scn, leader1.palf_handle_impl_->get_max_scn());
|
|
|
|
// 2. change to RAW_WRITE mode, not allow APPEND->FLASHBACK for now
|
|
switch_append_to_raw_write(leader1, mode_version1);
|
|
switch_append_to_raw_write(leader2, mode_version2);
|
|
|
|
// 3. do flashback
|
|
flashback_srv = get_cluster()[0]->get_flashback_service();
|
|
const int64_t TIMEOUT_US = 10 * 1000 * 1000;
|
|
|
|
// 4. test a follower blocknet
|
|
block_net(leader_idx1, (leader_idx1+1) % 3);
|
|
flashback_srv = get_cluster()[0]->get_flashback_service();
|
|
ASSERT_EQ(OB_OP_NOT_ALLOW, flashback_srv->flashback(MTL_ID(), flashback_scn, 5 * 1000 * 1000));
|
|
unblock_net(leader_idx1, (leader_idx1+1) % 3);
|
|
|
|
// test a learner blocknet
|
|
block_net(leader_idx1, 3);
|
|
flashback_srv = get_cluster()[0]->get_flashback_service();
|
|
ASSERT_EQ(OB_OP_NOT_ALLOW, flashback_srv->flashback(MTL_ID(), flashback_scn, 5 * 1000 * 1000));
|
|
unblock_net(leader_idx1, 3);
|
|
|
|
// 5. test basic flashback
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->flashback(MTL_ID(), flashback_scn, TIMEOUT_US));
|
|
LSN new_log_tail1 = leader1.palf_handle_impl_->log_engine_.log_storage_.log_tail_;
|
|
EXPECT_EQ(new_log_tail1, leader1.palf_handle_impl_->sw_.committed_end_lsn_);
|
|
EXPECT_GE(flashback_scn, leader1.palf_handle_impl_->sw_.last_slide_scn_);
|
|
EXPECT_EQ(OB_ITER_END, read_log(leader1));
|
|
wait_until_has_committed(leader1, leader1.palf_handle_impl_->sw_.get_max_lsn());
|
|
EXPECT_EQ(OB_ITER_END, read_log(leader1));
|
|
|
|
LSN new_log_tail2 = leader2.palf_handle_impl_->log_engine_.log_storage_.log_tail_;
|
|
EXPECT_EQ(new_log_tail2, leader2.palf_handle_impl_->sw_.committed_end_lsn_);
|
|
EXPECT_GE(flashback_scn, leader2.palf_handle_impl_->sw_.last_slide_scn_);
|
|
EXPECT_EQ(OB_ITER_END, read_log(leader2));
|
|
wait_until_has_committed(leader2, leader2.palf_handle_impl_->sw_.get_max_lsn());
|
|
EXPECT_EQ(OB_ITER_END, read_log(leader2));
|
|
|
|
std::vector<PalfHandleImplGuard*> palf_list1;
|
|
EXPECT_EQ(OB_SUCCESS, get_cluster_palf_handle_guard(id1, palf_list1));
|
|
EXPECT_GE(flashback_scn, palf_list1[3]->palf_handle_impl_->sw_.last_slide_scn_);
|
|
EXPECT_GE(flashback_scn, palf_list1[4]->palf_handle_impl_->sw_.last_slide_scn_);
|
|
revert_cluster_palf_handle_guard(palf_list1);
|
|
std::vector<PalfHandleImplGuard*> palf_list2;
|
|
EXPECT_EQ(OB_SUCCESS, get_cluster_palf_handle_guard(id1, palf_list2));
|
|
EXPECT_GE(flashback_scn, palf_list2[3]->palf_handle_impl_->sw_.last_slide_scn_);
|
|
EXPECT_GE(flashback_scn, palf_list2[4]->palf_handle_impl_->sw_.last_slide_scn_);
|
|
revert_cluster_palf_handle_guard(palf_list2);
|
|
// 4. delete paxos group
|
|
leader1.reset();
|
|
leader2.reset();
|
|
delete_paxos_group(id1);
|
|
delete_paxos_group(id2);
|
|
}
|
|
|
|
TEST_F(TestObSimpleLogClusterFlashback, flashback_with_reconfirm1)
|
|
{
|
|
SET_CASE_LOG_FILE(TEST_NAME, "flashback_reconfirm");
|
|
OB_LOGGER.set_log_level("TRACE");
|
|
const int64_t id1 = ATOMIC_AAF(&palf_id_, 1);
|
|
const int64_t CONFIG_CHANGE_TIMEOUT_US = 10 * 1000L * 1000L;
|
|
const int64_t TIMEOUT_US = 10 * 1000 * 1000;
|
|
int64_t leader_idx1 = 0;
|
|
int64_t mode_version1 = INVALID_PROPOSAL_ID, mode_version2 = INVALID_PROPOSAL_ID;
|
|
ObLogFlashbackService *flashback_srv = NULL;
|
|
// 1. create 2 palfs, each palf with 3 replicas
|
|
PalfHandleImplGuard leader1;
|
|
EXPECT_EQ(OB_SUCCESS, create_paxos_group(id1, leader_idx1, leader1));
|
|
if (leader_idx1 != 0) {
|
|
EXPECT_EQ(OB_SUCCESS, switch_leader(id1, 0, leader1));
|
|
}
|
|
LogConfigVersion config_version;
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_member(ObMember(get_cluster()[1]->get_addr(), 1), 2, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_member(ObMember(get_cluster()[2]->get_addr(), 1), 3, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_learner(ObMember(get_cluster()[3]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_learner(ObMember(get_cluster()[4]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, submit_log(leader1, 1000, leader_idx1));
|
|
wait_until_has_committed(leader1, leader1.palf_handle_impl_->get_max_lsn());
|
|
LogEntryHeader header_origin;
|
|
SCN flashback_scn;
|
|
EXPECT_EQ(OB_SUCCESS, get_middle_scn(602, leader1, flashback_scn, header_origin));
|
|
|
|
// 2. change to RAW_WRITE mode, not allow APPEND->FLASHBACK for now
|
|
switch_append_to_raw_write(leader1, mode_version1);
|
|
|
|
// 3. change to FLASHBACK mode
|
|
flashback_srv = get_cluster()[0]->get_flashback_service();
|
|
sleep(2);
|
|
share::ObLSStatusInfoArray ls_array;
|
|
const uint64_t tenant_id = MTL_ID();
|
|
ObLogFlashbackService::ChangeModeOpArray mode_op_array;
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_ls_list_(tenant_id, ls_array));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->wait_all_ls_replicas_log_sync_(tenant_id, flashback_scn, ls_array, TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_and_change_access_mode_(tenant_id, flashback_scn, palf::AccessMode::FLASHBACK, ls_array, TIMEOUT_US, mode_op_array));
|
|
// 4. leader do flashback
|
|
AccessMode unused_access_mode;
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_access_mode(mode_version1, unused_access_mode));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->flashback(mode_version1, flashback_scn, 1000 * 1000));
|
|
LogEntryHeader header_new;
|
|
SCN scn_new;
|
|
EXPECT_EQ(OB_SUCCESS, get_middle_scn(602, leader1, scn_new, header_new));
|
|
EXPECT_EQ(OB_ITER_END, get_middle_scn(603, leader1, scn_new, header_new));
|
|
PALF_LOG(INFO, "runlin trace get_middle_scn2");
|
|
EXPECT_EQ(scn_new, flashback_scn);
|
|
EXPECT_EQ(header_origin.data_checksum_, header_new.data_checksum_);
|
|
leader1.reset();
|
|
|
|
// 5. restart paxos group, server with smaller ip will be elected to leader
|
|
restart_paxos_groups();
|
|
|
|
// 6. get_leader and check values
|
|
std::vector<PalfHandleImplGuard*> palf_list;
|
|
EXPECT_EQ(OB_SUCCESS, get_cluster_palf_handle_guard(id1, palf_list));
|
|
EXPECT_EQ(OB_SUCCESS, get_leader(id1, leader1, leader_idx1));
|
|
if (leader_idx1 != 0) {
|
|
EXPECT_EQ(OB_SUCCESS, switch_leader(id1, 0, leader1));
|
|
}
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_access_mode(mode_version1, unused_access_mode));
|
|
EXPECT_EQ(AccessMode::FLASHBACK, unused_access_mode);
|
|
sleep(2);
|
|
EXPECT_EQ(OB_NOT_MASTER, submit_log(leader1, 1, leader_idx1));
|
|
EXPECT_GT(palf_list[1]->palf_handle_impl_->get_end_lsn(), leader1.palf_handle_impl_->get_end_lsn());
|
|
EXPECT_GE(flashback_scn, leader1.palf_handle_impl_->sw_.last_slide_scn_);
|
|
|
|
// 7. do flashback
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->flashback(tenant_id, flashback_scn, TIMEOUT_US));
|
|
LSN new_log_tail1 = leader1.palf_handle_impl_->log_engine_.log_storage_.log_tail_;
|
|
// in FLASHBACK mode, committed_end_lsn has been advanced to max_flshed_end_lsn by reconfirm
|
|
EXPECT_EQ(new_log_tail1.val_, leader1.palf_handle_impl_->sw_.committed_end_lsn_.val_);
|
|
EXPECT_GE(flashback_scn, leader1.palf_handle_impl_->sw_.last_slide_scn_);
|
|
|
|
// restart cluster
|
|
// we restart cluster after doing flashback operation, to
|
|
// validate if the operation of change_access_mode to APPEND can be done.
|
|
revert_cluster_palf_handle_guard(palf_list);
|
|
palf_list.clear();
|
|
leader1.reset();
|
|
restart_paxos_groups();
|
|
|
|
// 8. change to APPEND mode and submit_log
|
|
EXPECT_EQ(OB_SUCCESS, get_cluster_palf_handle_guard(id1, palf_list));
|
|
EXPECT_EQ(OB_SUCCESS, get_leader(id1, leader1, leader_idx1));
|
|
if (leader_idx1 != 0) {
|
|
EXPECT_EQ(OB_SUCCESS, switch_leader(id1, 0, leader1));
|
|
}
|
|
switch_flashback_to_append(leader1, mode_version1);
|
|
EXPECT_EQ(OB_SUCCESS, submit_log(leader1, 400, leader_idx1));
|
|
wait_until_has_committed(leader1, leader1.palf_handle_impl_->get_max_lsn());
|
|
|
|
flashback_scn.reset();
|
|
EXPECT_EQ(OB_SUCCESS, get_middle_scn(702, leader1, flashback_scn, header_origin));
|
|
|
|
// 9. change to RAW_WRITE mode, not allow APPEND->FLASHBACK for now
|
|
switch_append_to_raw_write(leader1, mode_version1);
|
|
|
|
// 10. change to FLASHBACK mode
|
|
flashback_srv = get_cluster()[0]->get_flashback_service();
|
|
sleep(2);
|
|
ls_array.reset();
|
|
mode_op_array.reset();
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_ls_list_(tenant_id, ls_array));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_and_change_access_mode_(tenant_id, flashback_scn, palf::AccessMode::PREPARE_FLASHBACK, ls_array, TIMEOUT_US, mode_op_array));
|
|
EXPECT_EQ(OB_NOT_MASTER, submit_log(leader1, 1, leader_idx1));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->wait_all_ls_replicas_log_sync_(tenant_id, flashback_scn, ls_array, TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_and_change_access_mode_(tenant_id, flashback_scn, palf::AccessMode::FLASHBACK, ls_array, TIMEOUT_US, mode_op_array));
|
|
|
|
// 11. two followers do flashback
|
|
do {
|
|
sleep(1);
|
|
palf_list[1]->palf_handle_impl_->get_access_mode(mode_version1, unused_access_mode);
|
|
} while (unused_access_mode != AccessMode::FLASHBACK);
|
|
do {
|
|
sleep(1);
|
|
palf_list[2]->palf_handle_impl_->get_access_mode(mode_version2, unused_access_mode);
|
|
} while (unused_access_mode != AccessMode::FLASHBACK);
|
|
EXPECT_EQ(OB_SUCCESS, palf_list[1]->palf_handle_impl_->flashback(mode_version1, flashback_scn, TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, palf_list[2]->palf_handle_impl_->flashback(mode_version2, flashback_scn, TIMEOUT_US));
|
|
|
|
// 11. restart paxos group, server with smaller ip will be elected to leader
|
|
revert_cluster_palf_handle_guard(palf_list);
|
|
palf_list.clear();
|
|
leader1.reset();
|
|
restart_paxos_groups();
|
|
|
|
// 12. get_leader and check values
|
|
EXPECT_EQ(OB_SUCCESS, get_cluster_palf_handle_guard(id1, palf_list));
|
|
EXPECT_EQ(OB_SUCCESS, get_leader(id1, leader1, leader_idx1));
|
|
if (leader_idx1 != 0) {
|
|
EXPECT_EQ(OB_SUCCESS, switch_leader(id1, 0, leader1));
|
|
}
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_access_mode(mode_version1, unused_access_mode));
|
|
EXPECT_EQ(AccessMode::FLASHBACK, unused_access_mode);
|
|
sleep(2);
|
|
EXPECT_EQ(OB_NOT_MASTER, submit_log(leader1, 1, leader_idx1));
|
|
EXPECT_GT(leader1.palf_handle_impl_->get_end_lsn(), palf_list[1]->palf_handle_impl_->get_end_lsn());
|
|
EXPECT_GT(leader1.palf_handle_impl_->get_end_lsn(), palf_list[2]->palf_handle_impl_->get_end_lsn());
|
|
|
|
// 13. do flashback
|
|
CLOG_LOG(INFO, "runlin trace begin last flashback", K(flashback_scn), K(leader1), K(leader_idx1),
|
|
"max_lsn:", leader1.palf_handle_impl_->sw_.last_submit_lsn_,
|
|
"max_scn:", leader1.palf_handle_impl_->sw_.get_max_scn(),
|
|
"last_slide_scn:", leader1.palf_handle_impl_->sw_.last_slide_scn_,
|
|
"committed_end_lsn:", leader1.palf_handle_impl_->sw_.committed_end_lsn_,
|
|
"log_storage_tail:", leader1.palf_handle_impl_->log_engine_.log_storage_.log_tail_);
|
|
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->flashback(tenant_id, flashback_scn, TIMEOUT_US));
|
|
|
|
CLOG_LOG(INFO, "runlin trace after last flashback", K(flashback_scn), K(leader1), K(leader_idx1),
|
|
"max_lsn:", leader1.palf_handle_impl_->sw_.last_submit_lsn_,
|
|
"max_scn:", leader1.palf_handle_impl_->sw_.get_max_scn(),
|
|
"last_slide_scn:", leader1.palf_handle_impl_->sw_.last_slide_scn_,
|
|
"committed_end_lsn:", leader1.palf_handle_impl_->sw_.committed_end_lsn_,
|
|
"log_storage_tail:", leader1.palf_handle_impl_->log_engine_.log_storage_.log_tail_);
|
|
|
|
EXPECT_GE(flashback_scn, leader1.palf_handle_impl_->sw_.last_slide_scn_);
|
|
new_log_tail1 = leader1.palf_handle_impl_->log_engine_.log_storage_.log_tail_;
|
|
EXPECT_EQ(new_log_tail1, leader1.palf_handle_impl_->sw_.committed_end_lsn_);
|
|
leader1.reset();
|
|
revert_cluster_palf_handle_guard(palf_list);
|
|
delete_paxos_group(id1);
|
|
}
|
|
|
|
// this case test flashback_scn is in (end_ts_ns, max_ts_ns)
|
|
TEST_F(TestObSimpleLogClusterFlashback, flashback_after_restart)
|
|
{
|
|
SET_CASE_LOG_FILE(TEST_NAME, "flashback_after_restart");
|
|
OB_LOGGER.set_log_level("INFO");
|
|
const int64_t id1 = ATOMIC_AAF(&palf_id_, 1);
|
|
const int64_t CONFIG_CHANGE_TIMEOUT_US = 10 * 1000L * 1000L;
|
|
const int64_t TIMEOUT_US = 10 * 1000 * 1000;
|
|
int64_t leader_idx1 = 0;
|
|
int64_t mode_version1 = INVALID_PROPOSAL_ID, mode_version2 = INVALID_PROPOSAL_ID;
|
|
ObLogFlashbackService *flashback_srv = NULL;
|
|
SCN flashback_scn = SCN::min_scn();
|
|
// 1. create 2 palfs, each palf with 3 replicas
|
|
PalfHandleImplGuard leader1;
|
|
EXPECT_EQ(OB_SUCCESS, create_paxos_group(id1, leader_idx1, leader1));
|
|
if (leader_idx1 != 0) {
|
|
EXPECT_EQ(OB_SUCCESS, switch_leader(id1, 0, leader1));
|
|
}
|
|
LogConfigVersion config_version;
|
|
const uint64_t tenant_id = MTL_ID();
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_member(ObMember(get_cluster()[1]->get_addr(), 1), 2, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
ASSERT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->get_config_version(config_version));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_member(ObMember(get_cluster()[2]->get_addr(), 1), 3, config_version, CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_learner(ObMember(get_cluster()[3]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, leader1.palf_handle_impl_->add_learner(ObMember(get_cluster()[4]->get_addr(), 1), CONFIG_CHANGE_TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, submit_log(leader1, 1000, leader_idx1));
|
|
wait_until_has_committed(leader1, leader1.palf_handle_impl_->get_max_lsn());
|
|
switch_append_to_raw_write(leader1, mode_version1);
|
|
|
|
// change to flasback mode
|
|
ObLogFlashbackService::ChangeModeOpArray mode_op_array;
|
|
share::ObLSStatusInfoArray ls_array;
|
|
flashback_srv = get_cluster()[0]->get_flashback_service();
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_ls_list_(tenant_id, ls_array));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->wait_all_ls_replicas_log_sync_(tenant_id, flashback_scn, ls_array, TIMEOUT_US));
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->get_and_change_access_mode_(tenant_id, flashback_scn, palf::AccessMode::FLASHBACK, ls_array, TIMEOUT_US, mode_op_array));
|
|
|
|
// after restarting servers in FLASHBACK MODE, committed_end_lsn will smaller than max_lsn
|
|
leader1.reset();
|
|
restart_paxos_groups();
|
|
|
|
EXPECT_EQ(OB_SUCCESS, get_leader(id1, leader1, leader_idx1));
|
|
if (leader_idx1 != 0) {
|
|
EXPECT_EQ(OB_SUCCESS, switch_leader(id1, 0, leader1));
|
|
}
|
|
// in FLASHBACK mode, committed_end_lsn has been advanced to max_flshed_end_lsn by reconfirm
|
|
EXPECT_EQ(leader1.palf_handle_impl_->get_max_lsn(), leader1.palf_handle_impl_->get_end_lsn());
|
|
EXPECT_EQ(leader1.palf_handle_impl_->get_max_scn(), leader1.palf_handle_impl_->get_end_scn());
|
|
|
|
// choose a flashback_scn, which is in (end_ts_ns, max_ts_ns)
|
|
flashback_scn.convert_for_tx((leader1.palf_handle_impl_->get_max_scn().get_val_for_inner_table_field() + leader1.palf_handle_impl_->get_end_scn().get_val_for_inner_table_field()) / 2);
|
|
EXPECT_EQ(OB_SUCCESS, flashback_srv->flashback(tenant_id, flashback_scn, TIMEOUT_US));
|
|
EXPECT_GE(flashback_scn, leader1.palf_handle_impl_->sw_.last_slide_scn_);
|
|
LSN new_log_tail1 = leader1.palf_handle_impl_->log_engine_.log_storage_.log_tail_;
|
|
EXPECT_EQ(new_log_tail1, leader1.palf_handle_impl_->sw_.committed_end_lsn_);
|
|
}
|
|
|
|
} // end unittest
|
|
} // end oceanbase
|
|
|
|
// Notes: How to write a new module integrate test case in logservice?
|
|
// 1. cp test_ob_simple_log_basic_func.cpp test_ob_simple_log_xxx.cpp
|
|
// 2. modify const string TEST_NAME, class name and log file name in test_ob_simple_log_xxx.cpp
|
|
// 3. add ob_unittest_clog() item and set label for test_ob_simple_log_xxx in unittest/cluster/CMakeFiles.txt
|
|
// 4. write new TEST_F
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
RUN_SIMPLE_LOG_CLUSTER_TEST(TEST_NAME);
|
|
}
|