/** * 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 #include "logservice/ob_log_handler.h" #include "logservice/rcservice/ob_role_change_handler.h" #include "logservice/rcservice/ob_role_change_service.h" #include "logservice/replayservice/ob_log_replay_service.h" #include "share/ob_ls_id.h" #include "storage/tx_storage/ob_ls_service.h" namespace oceanbase { using namespace common; using namespace palf; using namespace logservice; using namespace logservice; namespace unittest { class MockApplyService : public AppendCbWorker { public: int is_apply_done(const share::ObLSID &id, bool &is_done, LSN &lsn) { is_done = true; lsn = end_lsn_; PALF_LOG(INFO, "MockApplyService is_apply_done", K(id), K(is_done), K(lsn)); return OB_SUCCESS; } int push_append_cb(const int64_t id, AppendCb *cb, const LSN &lsn) { UNUSED(id); UNUSED(cb); UNUSED(lsn); return OB_SUCCESS; } void advance_end_lsn(const LSN &lsn) { end_lsn_ = lsn; } private: LSN end_lsn_; }; class MockReplayService : public logservice::ObILogReplayService { public: virtual int is_replay_done(const share::ObLSID &id, const palf::LSN &end_lsn, bool &is_done) { is_done = end_lsn <= end_lsn_; PALF_LOG(INFO, "MockReplayService is_replay_done", K(id), K(is_done), K(end_lsn)); return OB_SUCCESS; } virtual int switch_to_follower(const share::ObLSID &id, const palf::LSN &begin_lsn) { PALF_LOG(INFO, "MockReplayService switch_to_follower", K(id), K(begin_lsn)); return OB_SUCCESS; } virtual int switch_to_leader(const share::ObLSID &id) { PALF_LOG(INFO, "MockReplayService switch_to_leader", K(id)); return OB_SUCCESS; } void advance_end_lsn(const LSN &end_lsn) { end_lsn_ = end_lsn; } private: LSN end_lsn_; }; class MockObLogHandler : public logservice::ObILogHandler { public: MockObLogHandler() : curr_role_(FOLLOWER), curr_proposal_id_(-1), new_role_(FOLLOWER), new_proposal_id_(-1) {} virtual bool is_valid() const { return true; } virtual int append(const void *buffer, const int64_t nbytes, const int64_t ref_ts_ns, const bool need_nonblock, logservice::AppendCb *cb, palf::LSN &lsn, int64_t &ts_ns) { UNUSED(need_nonblock); UNUSED(buffer); UNUSED(nbytes); UNUSED(ref_ts_ns); UNUSED(cb); UNUSED(lsn); UNUSED(ts_ns); return OB_SUCCESS; } virtual int get_role(common::ObRole &role, int64_t &proposal_id) const { if (FOLLOWER == curr_role_) { role = curr_role_; proposal_id = curr_proposal_id_; } else { role = new_role_; proposal_id = curr_proposal_id_; } return OB_SUCCESS; } virtual int prepare_switch_role(common::ObRole &curr_role, int64_t &curr_proposal_id, common::ObRole &new_role, int64_t &new_proposal_id) { curr_role = curr_role_; curr_proposal_id = curr_proposal_id_; new_role = new_role_; new_proposal_id = new_proposal_id_; PALF_LOG(INFO, "MockObLogHandler prepare_switch_role", K(curr_role), K(curr_proposal_id), K(new_role), K(new_proposal_id)); return OB_SUCCESS; } virtual void switch_role(const common::ObRole &role, const int64_t proposal_id) { curr_role_ = role; curr_proposal_id_ = proposal_id; PALF_LOG(INFO, "MockObLogHandler switch_role", K(role), K(proposal_id)); } virtual int change_leader_to(const common::ObAddr &dst_addr) { UNUSED(dst_addr); return OB_SUCCESS; } virtual int revoke_leader() { curr_role_ = FOLLOWER; new_role_ = FOLLOWER; new_proposal_id_++; return OB_SUCCESS; } virtual int get_end_lsn(palf::LSN &end_lsn) const { end_lsn = LSN(1, 0); return OB_SUCCESS; } int seek(const palf::LSN &start_lsn, palf::PalfBufferIterator &iter) {UNUSED(start_lsn); UNUSED(iter); return OB_SUCCESS;}; int seek(const palf::LSN &start_lsn, const int64_t iterate_size, palf::PalfGroupBufferIterator &iter) {UNUSED(start_lsn); UNUSED(iterate_size); UNUSED(iter); return OB_SUCCESS;}; int seek(const int64_t start_ts_ns, palf::PalfGroupBufferIterator &iter) {UNUSED(start_ts_ns); UNUSED(iter); return OB_SUCCESS;}; int set_initial_member_list(const common::ObMemberList &member_list, const int64_t paxos_replica_num) {UNUSED(member_list); UNUSED(paxos_replica_num); return OB_SUCCESS;} int locate_by_ts_ns_coarsely(const int64_t ts_ns, palf::LSN &lsn) {UNUSED(ts_ns); UNUSED(lsn); return OB_SUCCESS;} int locate_by_lsn_coarsely(const palf::LSN &lsn, int64_t &ts_ns) {UNUSED(ts_ns); UNUSED(lsn); return OB_SUCCESS;} int advance_base_lsn(const palf::LSN &lsn) {UNUSED(lsn); return OB_SUCCESS;} int get_base_lsn(palf::LSN &lsn) {UNUSED(lsn); return OB_SUCCESS;} int get_base_ts_ns(int64_t &base_lsn_ts_ns) const {UNUSED(base_lsn_ts_ns); return OB_SUCCESS;} int get_end_ts_ns(int64_t &ts) const {UNUSED(ts); return OB_SUCCESS;} int get_paxos_member_list(common::ObMemberList &member_list, int64_t &paxos_replica_num) const {UNUSED(member_list); UNUSED(paxos_replica_num); return OB_SUCCESS;} int get_palf_base_info(const palf::LSN &base_lsn, palf::PalfBaseInfo &palf_base_info) { UNUSED(base_lsn); UNUSED(palf_base_info); return OB_SUCCESS; } int is_in_sync(bool &is_log_sync, bool &is_need_rebuild) const { UNUSED(is_log_sync); UNUSED(is_need_rebuild); return OB_SUCCESS; } bool is_sync_enabled() const { return true; } bool is_replay_enabled() const { return true; } int enable_sync() { return OB_SUCCESS; } int disable_sync() { return OB_SUCCESS; } int advance_base_lsn_for_rebuild(const palf::PalfBaseInfo &palf_base_info) { UNUSED(palf_base_info); return OB_SUCCESS; } TO_STRING_KV(K_(curr_role), K_(curr_proposal_id), K_(new_role), K_(new_proposal_id)); ObRole curr_role_; int64_t curr_proposal_id_; ObRole new_role_; int64_t new_proposal_id_; LSN end_lsn_; }; class TestObRoleChangeService : public ::testing::Test { public: TestObRoleChangeService() {} ~TestObRoleChangeService() {} protected: virtual void SetUp() { auto get_log_handler = [&](const share::ObLSID &ls_id, ObILogHandler *&log_handler) -> int { log_handler = &log_handler_; PALF_LOG(INFO, "get_log_handler", K(ls_id), KP(log_handler), K(log_handler_), KP(&log_handler_)); return OB_SUCCESS; }; auto get_role_change_handler = [&](const share::ObLSID &ls_id, ObRoleChangeHandler *&role_change_handler) -> int { role_change_handler = &role_change_handler_; PALF_LOG(INFO, "get_role_change_handler", K(ls_id), KP(role_change_handler)); return OB_SUCCESS; }; role_change_service_.init(&ls_service_, &apply_service_, &replay_service_); role_change_service_.start(); } virtual void TearDown() { role_change_service_.destroy(); } static void SetUpTestCase() { } static void TearDownTestCase() { } void palf_to_leader() { log_handler_.new_role_ = LEADER; log_handler_.new_proposal_id_++; PALF_LOG(INFO, "MockObLogHandler palf_to_leader", K(log_handler_), KP(&log_handler_)); } void palf_to_follower() { log_handler_.new_role_ = FOLLOWER; log_handler_.new_proposal_id_++; PALF_LOG(INFO, "MockObLogHandler palf_to_follower", K(log_handler_), KP(&log_handler_)); } MockApplyService apply_service_; MockReplayService replay_service_; ObLSService ls_service_; ObRoleChangeService role_change_service_; MockObLogHandler log_handler_; ObRoleChangeHandler role_change_handler_; }; TEST_F(TestObRoleChangeService, normal_case) { ObLSID ls_id(1); EXPECT_EQ(OB_SUCCESS, role_change_service_.on_role_change(ls_id.id())); usleep(10*1000); // new_proposal_id_ == curr_proposal_id_, no need change role EXPECT_EQ(FOLLOWER, log_handler_.curr_role_); palf_to_leader(); EXPECT_EQ(OB_SUCCESS, role_change_service_.on_role_change(ls_id.id())); LSN end_lsn(2, 0); usleep(10*1000); // before replay service replay done EXPECT_EQ(FOLLOWER, log_handler_.curr_role_); replay_service_.advance_end_lsn(end_lsn); usleep(10 * 1000); // follower to leader EXPECT_EQ(LEADER, log_handler_.curr_role_); palf_to_follower(); palf_to_leader(); // switch leader -> follower -> leader EXPECT_EQ(OB_SUCCESS, role_change_service_.on_role_change(ls_id.id())); usleep(10*1000); EXPECT_EQ(LEADER, log_handler_.curr_role_); palf_to_follower(); EXPECT_EQ(OB_SUCCESS, role_change_service_.on_role_change(ls_id.id())); usleep(10*1000); EXPECT_EQ(FOLLOWER, log_handler_.curr_role_); EXPECT_EQ(OB_SUCCESS, role_change_service_.on_role_change(ls_id.id())); palf_to_follower(); usleep(10*1000); EXPECT_EQ(FOLLOWER, log_handler_.curr_role_); } } // end of unittest } // end of oceanbase int main(int argc, char **argv) { system("rm -rf test_ob_role_change_service.*"); OB_LOGGER.set_file_name("test_ob_role_change_service.log", true); OB_LOGGER.set_log_level("INFO"); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }