[CP] [opt] avoid latency jitter of log replication when locking or unlock memberlist

This commit is contained in:
BinChenn 2024-02-10 05:08:24 +00:00 committed by ob-robot
parent 9ddcc1572c
commit 9a75df1e1a
13 changed files with 226 additions and 47 deletions

View File

@ -53,6 +53,13 @@ int MockElection::init(const int64_t id, const common::ObAddr &self)
return ret;
}
int MockElection::can_set_memberlist(const palf::LogConfigVersion &new_config_version) const
{
int ret = OB_SUCCESS;
UNUSED(new_config_version);
return ret;
}
int MockElection::set_memberlist(const MemberList &new_member_list)
{
int ret = OB_SUCCESS;

View File

@ -25,6 +25,7 @@ public:
virtual ~MockElection() { }
int init(const int64_t id, const common::ObAddr &self);
void stop() override final;
int can_set_memberlist(const palf::LogConfigVersion &new_config_version) const override final;
// 设置成员列表
int set_memberlist(const MemberList &new_member_list) override final;
// 获取选举当前的角色

View File

@ -799,6 +799,51 @@ TEST_F(TestObSimpleLogClusterArbService, test_1f1a_create_palf_group)
PALF_LOG(INFO, "end test_2f1a_degrade_upgrade", K(id));
}
// 1. 2F1A
// 2. lock_memberlist(just renew barrier)
// 3. submit and commit logs
// 4. kill leader
// 5. check committed_end_lsn
TEST_F(TestObSimpleLogClusterArbService, test_lock_memberlist_opt)
{
SET_CASE_LOG_FILE(TEST_NAME, "test_lock_memberlist_opt");
int ret = OB_SUCCESS;
const int64_t id = ATOMIC_AAF(&palf_id_, 1);
PALF_LOG(INFO, "begin test_repeat_lock_memberlist", K(id));
int64_t leader_idx = 0, arb_replica_idx = 0;
PalfHandleImplGuard leader;
oceanbase::common::ObClusterVersion::get_instance().cluster_version_ = CLUSTER_VERSION_4_2_0_0;
EXPECT_EQ(OB_SUCCESS, create_paxos_group_with_arb(id, arb_replica_idx, leader_idx, leader));
const int64_t CONFIG_CHANGE_TIMEOUT = 10 * 1000 * 1000L; // 10s
const int64_t another_f_idx = (leader_idx+1)%3;
EXPECT_EQ(OB_SUCCESS, submit_log(leader, 10, id));
EXPECT_UNTIL_EQ(leader.palf_handle_impl_->get_max_lsn(), leader.palf_handle_impl_->get_end_lsn());
// 2. renew_barrier
EXPECT_EQ(OB_SUCCESS, leader.palf_handle_impl_->config_mgr_.renew_config_change_barrier());
// 3. submit and commit logs
EXPECT_EQ(OB_SUCCESS, submit_log(leader, 10, id));
const LSN max_lsn = leader.palf_handle_impl_->get_max_lsn();
EXPECT_UNTIL_EQ(leader.palf_handle_impl_->get_max_lsn(), leader.palf_handle_impl_->get_end_lsn());
// 4. kill leader
block_all_net(leader_idx);
// 5. check committed_end_lsn
int64_t new_leader_idx = -1;
PalfHandleImplGuard new_leader;
EXPECT_EQ(OB_SUCCESS, get_leader(id, new_leader, new_leader_idx));
EXPECT_UNTIL_EQ(leader.palf_handle_impl_->get_max_lsn(), leader.palf_handle_impl_->get_end_lsn());
EXPECT_EQ(max_lsn, leader.palf_handle_impl_->get_end_lsn());
unblock_all_net(leader_idx);
leader.reset();
new_leader.reset();
delete_paxos_group(id);
PALF_LOG(INFO, "end test_lock_memberlist_opt", K(id));
}
} // end unittest
} // end oceanbase

View File

@ -154,6 +154,21 @@ void ElectionImpl::stop()
#undef PRINT_WRAPPER
}
int ElectionImpl::can_set_memberlist(const palf::LogConfigVersion &new_config_version) const
{
ELECT_TIME_GUARD(500_ms);
#define PRINT_WRAPPER KR(ret), K(*this), K(new_config_version)
int ret = common::OB_SUCCESS;
CHECK_ELECTION_ARGS(new_config_version);
LockGuard lock_guard(lock_);
CHECK_ELECTION_INIT();
if (CLICK_FAIL(proposer_.can_set_memberlist(new_config_version))) {
LOG_SET_MEMBER(WARN, "can_set_memberlist failed");
}
return ret;
#undef PRINT_WRAPPER
}
int ElectionImpl::set_memberlist(const MemberList &new_memberlist)
{
ELECT_TIME_GUARD(500_ms);

View File

@ -67,6 +67,7 @@ public:
const ObFunction<void(ElectionImpl *, common::ObRole, common::ObRole, RoleChangeReason)> &cb = DefaultRoleChangeCallBack());
int revoke(const RoleChangeReason &reason) override;
virtual void stop() override final;
virtual int can_set_memberlist(const palf::LogConfigVersion &new_config_version) const override final;
virtual int set_memberlist(const MemberList &new_memberlist) override final;
virtual int change_leader_to(const common::ObAddr &dest_addr) override final;
/**

View File

@ -98,15 +98,16 @@ int ElectionProposer::init(const int64_t restart_counter)
#undef PRINT_WRAPPER
}
int ElectionProposer::set_member_list(const MemberList &new_member_list)
int ElectionProposer::can_set_memberlist(const palf::LogConfigVersion &new_config_version) const
{
ELECT_TIME_GUARD(500_ms);
#define PRINT_WRAPPER K(*this), K(new_member_list)
#define PRINT_WRAPPER K(*this), K(new_config_version)
int ret = OB_SUCCESS;
// 检查旧的成员组的信息是否一致
const MemberList &current_member_list = memberlist_with_states_.get_member_list();
if (current_member_list.is_valid()) {
if (new_member_list.get_membership_version() < current_member_list.get_membership_version()) {
if (false == new_config_version.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_SET_MEMBER(ERROR, "invalid config_version");
} else if (current_member_list.is_valid()) {
if (new_config_version < current_member_list.get_membership_version()) {
ret = OB_INVALID_ARGUMENT;
LOG_SET_MEMBER(ERROR, "new memberlsit's membership version is not greater than current");
} else if (check_leader()) {
@ -116,7 +117,19 @@ int ElectionProposer::set_member_list(const MemberList &new_member_list)
}
}
}
if (OB_SUCC(ret)) {
return ret;
#undef PRINT_WRAPPER
}
int ElectionProposer::set_member_list(const MemberList &new_member_list)
{
ELECT_TIME_GUARD(500_ms);
#define PRINT_WRAPPER K(*this), K(new_member_list)
int ret = OB_SUCCESS;
// 检查旧的成员组的信息是否一致
if (OB_FAIL(can_set_memberlist(new_member_list.get_membership_version()))) {
LOG_SET_MEMBER(WARN, "can_set_memberlist failed");
} else {
MemberList old_list = memberlist_with_states_.get_member_list();
if (CLICK_FAIL(memberlist_with_states_.set_member_list(new_member_list))) {
LOG_SET_MEMBER(WARN, "set new member list failed");

View File

@ -49,6 +49,14 @@ class ElectionProposer
public:
ElectionProposer(ElectionImpl *election);
int init(const int64_t restart_counter);
/**
* @description: whether the new config version can be set to the election module
* @param {LogConfigVersion} &new_config_version
* @return {int} OB_INVALID_ARGUMENT : invalid or too small config_version
OB_OP_NOT_ALLOWED : current config_version hasn't been synchronized to any majority
* @Date: 2021-12-23 11:33:50
*/
int can_set_memberlist(const palf::LogConfigVersion &new_config_version) const;
/**
* @description:
* @param {MemberList} &new_member_list

View File

@ -63,6 +63,7 @@ class Election
public:
virtual ~Election() {}
virtual void stop() = 0;
virtual int can_set_memberlist(const palf::LogConfigVersion &new_config_version) const = 0;
// 设置成员列表
virtual int set_memberlist(const MemberList &new_member_list) = 0;
// 获取选举当前的角色

View File

@ -878,9 +878,8 @@ int LogConfigMgr::change_config_(const LogConfigChangeArgs &args,
}
case (ConfigChangeState::CHANGING): {
if (is_reach_majority_()) {
(void) state_mgr_->reset_changing_config_with_arb();
(void) after_config_log_majority_(proposal_id, config_version);
state_ = INIT;
(void) update_match_lsn_map_(running_args_, log_ms_meta_.curr_);
ms_ack_list_.reset();
resend_config_version_ = log_ms_meta_.curr_.config_.config_version_;
last_submit_config_log_time_us_ = OB_INVALID_TIMESTAMP;
@ -2061,9 +2060,11 @@ int LogConfigMgr::receive_config_log(const common::ObAddr &leader, const LogConf
int LogConfigMgr::ack_config_log(const common::ObAddr &sender,
const int64_t proposal_id,
const LogConfigVersion &config_version)
const LogConfigVersion &config_version,
bool &is_majority)
{
int ret = OB_SUCCESS;
is_majority = false;
SpinLockGuard guard(lock_);
const bool is_in_memberlist = alive_paxos_memberlist_.contains(sender);
if (IS_NOT_INIT) {
@ -2084,14 +2085,45 @@ int LogConfigMgr::ack_config_log(const common::ObAddr &sender,
} else {
ret = OB_SUCCESS;
// NB: can set majority repeatedly.
bool majority = is_reach_majority_();
is_majority = is_reach_majority_();
PALF_LOG(INFO, "ack_config_log success", KR(ret), K_(palf_id), K_(self), K(config_version), K(sender),
K(majority), K_(ms_ack_list), K(alive_paxos_replica_num_));
K(is_majority), K_(ms_ack_list), K(alive_paxos_replica_num_));
}
}
return ret;
}
int LogConfigMgr::after_config_log_majority(const int64_t proposal_id,
const LogConfigVersion &config_version)
{
int ret = OB_SUCCESS;
SpinLockGuard guard(lock_);
if (IS_NOT_INIT) {
ret = OB_NOT_INIT;
PALF_LOG(WARN, "LogConfigMgr not init", KR(ret));
} else {
ret = after_config_log_majority_(proposal_id, config_version);
}
return ret;
}
// do not change LogConfigMgr::state_
int LogConfigMgr::after_config_log_majority_(const int64_t proposal_id,
const LogConfigVersion &config_version)
{
int ret = OB_SUCCESS;
if (proposal_id != log_ms_meta_.proposal_id_ ||
config_version != log_ms_meta_.curr_.config_.config_version_) {
ret = OB_STATE_NOT_MATCH;
PALF_LOG(WARN, "config_version has been changed", KR(ret), K_(palf_id),
K_(self), K_(log_ms_meta), K(proposal_id), K_(state), K(config_version));
} else if (is_reach_majority_()) {
(void) state_mgr_->reset_changing_config_with_arb();
(void) update_match_lsn_map_(running_args_, log_ms_meta_.curr_);
}
return ret;
}
int LogConfigMgr::try_resend_config_log_(const int64_t proposal_id)
{
int ret = OB_SUCCESS;

View File

@ -180,6 +180,12 @@ inline bool is_may_change_replica_num(const LogConfigChangeType type)
return is_add_member_list(type) || is_remove_member_list(type) || CHANGE_REPLICA_NUM == type || FORCE_SINGLE_MEMBER == type;
}
inline bool is_must_not_change_replica_num(const LogConfigChangeType type)
{
return ADD_LEARNER == type || REMOVE_LEARNER == type || REPLACE_LEARNERS == type ||
TRY_LOCK_CONFIG_CHANGE == type || UNLOCK_CONFIG_CHANGE == type;
}
inline bool is_paxos_member_list_change(const LogConfigChangeType type)
{
return (ADD_MEMBER == type || REMOVE_MEMBER == type
@ -462,8 +468,11 @@ public:
// for PalfHandleImpl::ack_config_log
virtual int ack_config_log(const common::ObAddr &sender,
const int64_t proposal_id,
const LogConfigVersion &config_version);
const int64_t proposal_id,
const LogConfigVersion &config_version,
bool &is_majority);
virtual int after_config_log_majority(const int64_t proposal_id,
const LogConfigVersion &config_version);
int wait_config_log_persistence(const LogConfigVersion &config_version) const;
// broadcast leader info to global learners, only called in leader active
virtual int submit_broadcast_leader_info(const int64_t proposal_id) const;
@ -596,6 +605,9 @@ private:
int pre_sync_config_log_and_mode_meta_(const common::ObMember &server,
const int64_t proposal_id,
const bool is_arb_replica);
int after_config_log_majority_(const int64_t proposal_id,
const LogConfigVersion &config_version);
private:
// inner_config_meta_ is protected by RWLock in PalfHandleImpl,
// any read/write ops to inner_config_meta_ should acquire RLock/WLock in PalfHandleImpl.

View File

@ -1236,8 +1236,9 @@ int PalfHandleImpl::wait_log_barrier_(const LogConfigChangeArgs &args,
TimeoutChecker &not_timeout)
{
int ret = OB_SUCCESS;
bool has_renew_barrier = false;
while (OB_SUCC(ret) && OB_SUCC(not_timeout())) {
bool need_wlock = (false == state_mgr_.is_changing_config_with_arb());
bool need_wlock = !has_renew_barrier;
bool need_rlock = !need_wlock;
if (DEGRADE_ACCEPTOR_TO_LEARNER != args.type_ &&
true == ATOMIC_LOAD(&has_higher_prio_config_change_)) {
@ -1248,10 +1249,17 @@ int PalfHandleImpl::wait_log_barrier_(const LogConfigChangeArgs &args,
}
if (true == need_wlock) {
WLockGuard guard(lock_);
// if the reconfiguration request do not change memberlist or replica_num,
// it's safe to commit logs after the reconfiguration barrier before the
// reconfiguration log is committed.
const bool do_not_change_quorum = is_must_not_change_replica_num(args.type_);
if (OB_FAIL(config_mgr_.renew_config_change_barrier())) {
PALF_LOG(WARN, "renew_config_change_barrier failed", KR(ret), KPC(this), K(args));
} else if (OB_FAIL(state_mgr_.set_changing_config_with_arb())) {
} else if (false == do_not_change_quorum &&
OB_FAIL(state_mgr_.set_changing_config_with_arb())) {
PALF_LOG(WARN, "set_changing_config_with_arb failed", KR(ret), KPC(this), K(args));
} else {
has_renew_barrier = true;
}
} else if (true == need_rlock) {
RLockGuard guard(lock_);
@ -1259,11 +1267,13 @@ int PalfHandleImpl::wait_log_barrier_(const LogConfigChangeArgs &args,
PALF_LOG(WARN, "wait_log_barrier_ failed", KR(ret), KPC(this), K(args));
} else if (OB_EAGAIN == ret) {
ret = OB_SUCCESS;
ob_usleep(10 * 1000);
} else {
break;
}
}
if (OB_SUCC(ret) && true == need_rlock) {
ob_usleep(10 * 1000);
}
}
return ret;
}
@ -1357,12 +1367,30 @@ int PalfHandleImpl::one_stage_config_change_(const LogConfigChangeArgs &args,
}
}
time_guard.click("precheck");
// step 3: waiting for log barrier if a arbitration member exists
// step 3: check whether the new config info can be set to the election module
while (OB_SUCCESS == ret && OB_SUCC(not_timeout())) {
{
RLockGuard guard(lock_);
LogConfigVersion config_version;
if (OB_FAIL(config_mgr_.get_config_version(config_version))) {
PALF_LOG(WARN, "get_config_version failed", KR(ret), KPC(this), K(config_version));
} else if (OB_FAIL(config_version.inc_update_version(proposal_id))) {
PALF_LOG(WARN, "inc_update_version failed", KR(ret), KPC(this), K(config_version));
} else if (OB_FAIL(election_.can_set_memberlist(config_version))) {
ret = (OB_OP_NOT_ALLOW == ret)? OB_SUCCESS: ret;
} else {
break;
}
}
ob_usleep(50 * 1000);
}
time_guard.click("wait_ele");
// step 4: waiting for log barrier if a arbitration member exists
if (OB_SUCC(ret) && true == new_config_info.config_.arbitration_member_.is_valid()) {
ret = wait_log_barrier_(args, new_config_info, not_timeout);
}
time_guard.click("wait_barrier");
// step 4: motivate reconfiguration
// step 5: motivate reconfiguration
while (OB_SUCCESS == ret && OB_SUCC(not_timeout())) {
bool need_wlock = false;
bool need_rlock = false;
@ -1387,7 +1415,7 @@ int PalfHandleImpl::one_stage_config_change_(const LogConfigChangeArgs &args,
break;
}
if (false == need_rlock && false == need_wlock) {
const int64_t SLEEP_US = (state_mgr_.is_changing_config_with_arb())? 10 * 1000: 50 * 1000;
const int64_t SLEEP_US = (state_mgr_.is_changing_config_with_arb())? 1 * 1000: 50 * 1000;
ob_usleep(SLEEP_US);
}
if (true == need_wlock) {
@ -4050,22 +4078,29 @@ int PalfHandleImpl::ack_config_log(const common::ObAddr &server,
const LogConfigVersion &config_version)
{
int ret = OB_SUCCESS;
RLockGuard guard(lock_);
const int64_t &curr_proposal_id = state_mgr_.get_proposal_id();
if (IS_NOT_INIT) {
ret = OB_NOT_INIT;
PALF_LOG(WARN, "PalfHandleImpl not init", KR(ret));
} else if (msg_proposal_id != curr_proposal_id) {
PALF_LOG(WARN, "proposal_id does not match", KR(ret), KPC(this), K(msg_proposal_id),
K(server), K(curr_proposal_id));
} else if (self_ != state_mgr_.get_leader()) {
ret = OB_STATE_NOT_MATCH;
PALF_LOG(WARN, "self is not leader, state not match", KR(ret), KPC(this),
K(server), K(msg_proposal_id), K(curr_proposal_id));
} else if (OB_FAIL(config_mgr_.ack_config_log(server, msg_proposal_id, config_version))) {
PALF_LOG(WARN, "ObLogConfigMgr ack_config_log failed", KR(ret), KPC(this), K(server), K(msg_proposal_id), K(config_version));
} else {
PALF_LOG(INFO, "ack_config_log success", KR(ret), KPC(this), K(server), K(msg_proposal_id), K(config_version));
bool is_majority = false;
do {
RLockGuard guard(lock_);
const int64_t &curr_proposal_id = state_mgr_.get_proposal_id();
if (IS_NOT_INIT) {
ret = OB_NOT_INIT;
PALF_LOG(WARN, "PalfHandleImpl not init", KR(ret));
} else if (msg_proposal_id != curr_proposal_id) {
PALF_LOG(WARN, "proposal_id does not match", KR(ret), KPC(this), K(msg_proposal_id),
K(server), K(curr_proposal_id));
} else if (self_ != state_mgr_.get_leader()) {
ret = OB_STATE_NOT_MATCH;
PALF_LOG(WARN, "self is not leader, state not match", KR(ret), KPC(this),
K(server), K(msg_proposal_id), K(curr_proposal_id));
} else if (OB_FAIL(config_mgr_.ack_config_log(server, msg_proposal_id, config_version, is_majority))) {
PALF_LOG(WARN, "ObLogConfigMgr ack_config_log failed", KR(ret), KPC(this), K(server), K(msg_proposal_id), K(config_version));
} else {
PALF_LOG(INFO, "ack_config_log success", KR(ret), KPC(this), K(server), K(msg_proposal_id), K(config_version));
}
} while (0);
if (is_majority) {
WLockGuard guard(lock_);
(void) config_mgr_.after_config_log_majority(msg_proposal_id, config_version);
}
return ret;
}
@ -4215,7 +4250,8 @@ int PalfHandleImpl::after_flush_config_change_meta_(const int64_t proposal_id, c
PALF_LOG(WARN, "LogConfigMgr after_flush_config_log failed", K(ret), KPC(this), K(proposal_id),
K(config_version));
} else if (self_ == leader) {
if (OB_FAIL(config_mgr_.ack_config_log(self_, proposal_id, config_version))) {
bool unused_bool = false;
if (OB_FAIL(config_mgr_.ack_config_log(self_, proposal_id, config_version, unused_bool))) {
PALF_LOG(WARN, "ack_config_log failed", K(ret), KPC(this), K(config_version));
}
} else if (false == leader.is_valid()) {

View File

@ -36,6 +36,12 @@ public:
}
void stop() override final
{}
int can_set_memberlist(const palf::LogConfigVersion &new_config_version) const override final
{
int ret = OB_SUCCESS;
UNUSED(new_config_version);
return ret;
}
// 设置成员列表
int set_memberlist(const MemberList &new_member_list) override final
{

View File

@ -1371,19 +1371,20 @@ TEST_F(TestLogConfigMgr, test_submit_start_working_log)
EXPECT_EQ(OB_EAGAIN, cm.confirm_start_working_log(INIT_PROPOSAL_ID, INIT_ELE_EPOCH, sw_config_version));
EXPECT_GT(cm.last_submit_config_log_time_us_, 0);
// ack defensive code
EXPECT_EQ(OB_STATE_NOT_MATCH, cm.ack_config_log(addr2, 2, expect_config_version));
EXPECT_EQ(OB_STATE_NOT_MATCH, cm.ack_config_log(addr2, 1, LogConfigVersion()));
bool unused_bool = false;
EXPECT_EQ(OB_STATE_NOT_MATCH, cm.ack_config_log(addr2, 2, expect_config_version, unused_bool));
EXPECT_EQ(OB_STATE_NOT_MATCH, cm.ack_config_log(addr2, 1, LogConfigVersion(), unused_bool));
// receive ack from learner
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr4, 1, expect_config_version));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr4, 1, expect_config_version, unused_bool));
EXPECT_EQ(0, cm.ms_ack_list_.get_count());
EXPECT_EQ(2, cm.resend_log_list_.get_member_number());
EXPECT_EQ(OB_EAGAIN, cm.confirm_start_working_log(INIT_PROPOSAL_ID, INIT_ELE_EPOCH, sw_config_version));
// receive ack from member
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr1, 1, expect_config_version));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr1, 1, expect_config_version, unused_bool));
EXPECT_EQ(1, cm.ms_ack_list_.get_count());
EXPECT_EQ(2, cm.resend_log_list_.get_member_number());
EXPECT_EQ(OB_EAGAIN, cm.confirm_start_working_log(INIT_PROPOSAL_ID, INIT_ELE_EPOCH, sw_config_version));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr2, 1, expect_config_version));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr2, 1, expect_config_version, unused_bool));
EXPECT_EQ(2, cm.ms_ack_list_.get_count());
EXPECT_EQ(1, cm.resend_log_list_.get_member_number());
// check if config log is committed
@ -1396,7 +1397,7 @@ TEST_F(TestLogConfigMgr, test_submit_start_working_log)
cm.last_submit_config_log_time_us_ = 0;
EXPECT_EQ(OB_SUCCESS, cm.try_resend_config_log_(1));
// receive ack from last member
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr3, 1, expect_config_version));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr3, 1, expect_config_version, unused_bool));
EXPECT_EQ(0, cm.ms_ack_list_.get_count());
EXPECT_EQ(0, cm.resend_log_list_.get_member_number());
}
@ -1618,13 +1619,14 @@ TEST_F(TestLogConfigMgr, test_degrade_upgrade_scenario)
// member_list will not take effect after append_config_meta_
EXPECT_FALSE(cm.log_ms_meta_.curr_.config_.log_sync_memberlist_.contains(addr2));
// self ack config log
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr1, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_));
bool unused_bool = false;
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr1, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_, unused_bool));
// reach majority - 1
EXPECT_EQ(OB_EAGAIN, cm.change_config(args, INIT_PROPOSAL_ID, INIT_ELE_EPOCH, de_config_version));
EXPECT_EQ(1, cm.state_);
EXPECT_FALSE(cm.log_ms_meta_.curr_.config_.log_sync_memberlist_.contains(addr2));
// ack config log
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr3, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr3, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_, unused_bool));
// degrade success, switch to INIT state
EXPECT_EQ(OB_SUCCESS, cm.change_config(args, INIT_PROPOSAL_ID, INIT_ELE_EPOCH, de_config_version));
EXPECT_EQ(0, cm.state_);
@ -1638,13 +1640,13 @@ TEST_F(TestLogConfigMgr, test_degrade_upgrade_scenario)
// member_list will not take effect after append_config_meta_
EXPECT_TRUE(cm.log_ms_meta_.curr_.config_.log_sync_memberlist_.contains(addr2));
// self ack config log
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr1, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr1, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_, unused_bool));
// reach majority - 1
EXPECT_EQ(OB_EAGAIN, cm.change_config(up_args, INIT_PROPOSAL_ID, INIT_ELE_EPOCH, up_config_version));
EXPECT_TRUE(cm.log_ms_meta_.curr_.config_.log_sync_memberlist_.contains(addr2));
EXPECT_EQ(1, cm.state_);
// ack config log
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr3, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_));
EXPECT_EQ(OB_SUCCESS, cm.ack_config_log(addr3, cm.log_ms_meta_.proposal_id_, cm.log_ms_meta_.curr_.config_.config_version_, unused_bool));
// degrade success, switch to INIT state
EXPECT_EQ(OB_SUCCESS, cm.change_config(args, INIT_PROPOSAL_ID, INIT_ELE_EPOCH, up_config_version));
EXPECT_EQ(0, cm.state_);