190 lines
5.7 KiB
C++
190 lines
5.7 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.
|
|
*/
|
|
|
|
#ifndef _OB_ELECTION_TESTER_
|
|
#define _OB_ELECTION_TESTER_
|
|
|
|
#include "lib/allocator/page_arena.h"
|
|
#include "common/ob_server.h"
|
|
#include "common/ob_array_helper.h"
|
|
#include "election/ob_election_server.h"
|
|
#include "election/ob_election_rpc.h"
|
|
#include "mock_election_rpc.h"
|
|
#include "mock_election_clock.h"
|
|
|
|
#define NOW (::oceanbase::common::ObTimeUtility::current_time() / 1000)
|
|
#define NEXT_T_CYCLE(ts) (ts) - ((ts) % (T_CYCLE)) + (T_CYCLE)
|
|
#define NEXT_T_ELECT2(ts) (ts) - ((ts) % (T_ELECT2)) + (T_ELECT2)
|
|
#define DECENTRALIZED_VOTE_START ((NOW) + (T_CYCLE) + (T_CYCLE)-1) / (T_CYCLE) * (T_CYCLE)
|
|
|
|
namespace oceanbase {
|
|
namespace tests {
|
|
namespace election {
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::election;
|
|
|
|
/*usage:
|
|
|
|
ObElectionTesterCluster cluster;
|
|
ObElectionTester t1, t2, t3;
|
|
|
|
t1.set_candidate()
|
|
.set_packet_loss(DECENTRALIZED_DO_VOTE, ObElectionTester::IN, INT_MIN, INT_MAX)
|
|
.clock_skew(timeout)
|
|
.add_to(cluster);
|
|
t2.set_candidate()
|
|
.set_packet_loss(DECENTRALIZED_DO_VOTE, ObElectionTester::IN, INT_MIN, INT_MAX)
|
|
.clock_skew(timeout)
|
|
.add_to(cluster);
|
|
t3.set_candidate()
|
|
.set_packet_loss(DECENTRALIZED_DO_VOTE, ObElectionTester::IN, INT_MIN, INT_MAX)
|
|
.clock_skew(timeout)
|
|
.add_to(cluster);
|
|
|
|
cluster.init(dev_name).start();
|
|
sleep(3);
|
|
t1.restart();
|
|
sleep(4);
|
|
|
|
ASSERT(t1.has_leader() && t1.get_current_leader() == t1)
|
|
*/
|
|
class ObElectionTesterCluster;
|
|
class MockClockSkew;
|
|
class MockClockSkewRandom;
|
|
class MockObElectionRpcStub;
|
|
class ObElectionTester {
|
|
friend class ObElectionTesterCluster;
|
|
|
|
public:
|
|
enum InitialState { NORMAL_MODE = 0, RANDOM_MOCK, MOCK };
|
|
enum NetWorkDirection { INVALID = 0, IN, OUT, IN_OUT };
|
|
|
|
public:
|
|
ObElectionTester();
|
|
~ObElectionTester();
|
|
|
|
inline ObElectionTester& set_candidate();
|
|
inline bool is_candidate() const;
|
|
void destroy(void);
|
|
void create(void);
|
|
|
|
public:
|
|
ObElectionTester& set_packet_loss_all(NetWorkDirection direction, int64_t start, int64_t end);
|
|
ObElectionTester& set_packet_loss(ObElectionVoteMsgType type, NetWorkDirection direction, int64_t start, int64_t end);
|
|
ObElectionTester& set_random_packet_loss(
|
|
NetWorkDirection direction, int64_t loss_rate, int64_t start = INT64_MIN, int64_t end = INT64_MAX);
|
|
|
|
ObElectionTester& clock_skew(int64_t ts);
|
|
ObElectionTester& clock_skew_random(int64_t t1, int64_t t2);
|
|
|
|
int start(void);
|
|
void stop(void);
|
|
void restart(void);
|
|
|
|
ObElectionTester* get_current_leader(void) const;
|
|
ObElectionTester& add_to(ObElectionTesterCluster& cluster);
|
|
const ObServer& get_self() const;
|
|
|
|
public:
|
|
void reset_rpc(void);
|
|
void reset_clock(void);
|
|
void reset_msg_handler(void);
|
|
int get_port(void) const;
|
|
void set_port(const int32_t port);
|
|
|
|
bool has_leader() const;
|
|
bool is_real_leader() const;
|
|
bool operator==(const ObServer& server) const;
|
|
|
|
private:
|
|
int init(const char* dev_name, const ObList<ObServer, common::ObIAllocator>& voters,
|
|
const ObList<ObServer, common::ObIAllocator>& candidates, const ObList<ObServer, common::ObIAllocator>& watchers);
|
|
|
|
MockClockSkew* clock_skew_;
|
|
MockClockSkewRandom* clock_skew_random_;
|
|
|
|
MockObElectionRpcStub* rpc_loss_;
|
|
MockObElectionRpcStub* rpc_random_loss_;
|
|
|
|
MockObElectionMsgHandler* msg_handler_loss_;
|
|
MockObElectionMsgHandler* msg_handler_random_loss_;
|
|
|
|
private:
|
|
ObElectionServer* server_; // election server wrapped by this class
|
|
ObElectionTesterCluster* cluster_; // cluster this tester belongs to
|
|
InitialState skew_stat_;
|
|
InitialState rpc_recv_stat_;
|
|
InitialState rpc_send_stat_;
|
|
|
|
private:
|
|
bool inited_; // we need two step of init
|
|
int port_;
|
|
ObElectionMemberType server_role_;
|
|
obsys::CRWLock mutex_;
|
|
};
|
|
|
|
class ObElectionTesterCluster {
|
|
friend class ObElectionTester;
|
|
|
|
public:
|
|
ObElectionTesterCluster();
|
|
ObElectionTesterCluster& init();
|
|
ObElectionTesterCluster& init(const char* dev_name);
|
|
void start(void);
|
|
void stop(void);
|
|
inline int64_t get_server_count() const;
|
|
bool have_leader_agreement(void) const;
|
|
bool have_leader_agreement(const ObElectionTester* leader) const;
|
|
ObElectionTester* get_tester(const ObServer& server);
|
|
ObElectionTester* get_one_slave(void) const;
|
|
|
|
private:
|
|
static int port;
|
|
static const char* devname;
|
|
// calc servers and push them into three list according to server role
|
|
int calculate_roles();
|
|
int remove(const ObElectionTester* tester);
|
|
bool add(ObElectionTester* tester);
|
|
|
|
private:
|
|
static const int MAX_TESTER = 64;
|
|
ObElectionTester* vtester_[MAX_TESTER];
|
|
ObArrayHelper<ObElectionTester*> array_helper_;
|
|
common::ObArenaAllocator allocator_;
|
|
ObList<ObServer, common::ObIAllocator> voters_;
|
|
ObList<ObServer, common::ObIAllocator> candidates_;
|
|
ObList<ObServer, common::ObIAllocator> watchers_;
|
|
uint32_t local_ip_;
|
|
const char* dev_name_;
|
|
bool inited_; // we need two step of init
|
|
};
|
|
inline int64_t ObElectionTesterCluster::get_server_count() const
|
|
{
|
|
return array_helper_.get_array_index();
|
|
}
|
|
|
|
inline ObElectionTester& ObElectionTester::set_candidate()
|
|
{
|
|
server_role_ = MEMBER_TYPE_CANDIDATE;
|
|
return *this;
|
|
}
|
|
|
|
inline bool ObElectionTester::is_candidate() const
|
|
{
|
|
return server_role_ == MEMBER_TYPE_CANDIDATE;
|
|
}
|
|
} // namespace election
|
|
} // namespace tests
|
|
} // namespace oceanbase
|
|
|
|
#endif
|