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