323 lines
9.6 KiB
C++
323 lines
9.6 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 "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();
|
|
}
|