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