Unverified Commit 73a3a856 authored by Ozan Tezcan's avatar Ozan Tezcan Committed by GitHub
Browse files

Prevote implementation (#52)

* prevote implementation
parent bdd0797f
......@@ -28,17 +28,17 @@ typedef enum {
RAFT_MEMBERSHIP_REMOVE,
} raft_membership_e;
#define RAFT_UNKNOWN_NODE_ID (-1)
typedef enum {
RAFT_STATE_NONE,
RAFT_STATE_FOLLOWER,
RAFT_STATE_PRECANDIDATE,
RAFT_STATE_CANDIDATE,
RAFT_STATE_LEADER
} raft_state_e;
/** Allow entries to apply while taking a snapshot */
#define RAFT_SNAPSHOT_NONBLOCKING_APPLY 1
#define RAFT_NODE_ID_NONE (-1)
typedef enum {
/**
......@@ -131,6 +131,9 @@ typedef struct
* This message could force a leader/candidate to become a follower. */
typedef struct
{
/** 1 if this is a prevote message, 0 otherwise */
int prevote;
/** currentTerm, to force other leader/candidate to step down */
raft_term_t term;
......@@ -148,6 +151,12 @@ typedef struct
* Indicates if node has accepted the server's vote request. */
typedef struct
{
/** 1 if this is a prevote message, 0 otherwise */
int prevote;
/** term of received requestvote msg */
raft_term_t request_term;
/** currentTerm, for candidate to update itself */
raft_term_t term;
......@@ -285,7 +294,7 @@ typedef int (
* This callback is optional
* @param[in] raft The Raft server making this callback
* @param[in] node_id The node id that is the subject of this log. If log is not
* related to a node, this could be 'RAFT_UNKNOWN_NODE_ID'.
* related to a node, this could be 'RAFT_NODE_ID_NONE'.
* @param[in] user_data User data that is passed from Raft server
* @param[in] buf The buffer that was logged */
typedef void (
......@@ -818,6 +827,10 @@ int raft_is_follower(raft_server_t* me);
* @return 1 if leader; 0 otherwise */
int raft_is_leader(raft_server_t* me);
/**
* @return 1 if precandidate; 0 otherwise */
int raft_is_precandidate(raft_server_t* me);
/**
* @return 1 if candidate; 0 otherwise */
int raft_is_candidate(raft_server_t* me);
......@@ -883,7 +896,7 @@ int raft_get_voted_for(raft_server_t* me);
/** Get what this node thinks the node ID of the leader is.
* @return node of what this node thinks is the valid leader;
* RAFT_UNKNOWN_NODE_ID if there is no leader */
* RAFT_NODE_ID_NONE if there is no leader */
raft_node_id_t raft_get_leader_id(raft_server_t* me_);
/** Get what this node thinks the node of the leader is.
......
......@@ -75,7 +75,7 @@ typedef struct {
raft_msg_id_t last_acked_msg_id;
/* what this node thinks is the node ID of the current leader or
* RAFT_UNKNOWN_NODE_ID if there isn't a known current leader. */
* RAFT_NODE_ID_NONE if there isn't a known current leader. */
raft_node_id_t leader_id;
/* callbacks */
......@@ -121,6 +121,8 @@ int raft_election_start(raft_server_t* me);
int raft_become_candidate(raft_server_t* me);
int raft_become_precandidate(raft_server_t* me);
void raft_randomize_election_timeout(raft_server_t* me_);
void raft_update_quorum_meta(raft_server_t* me_, raft_msg_id_t id);
......
......@@ -72,7 +72,7 @@ static void raft_log_node(raft_server_t *me_,
me->cb.log(me_, id, me->udata, buf);
}
#define raft_log(me, ...) (raft_log_node(me, RAFT_UNKNOWN_NODE_ID, __VA_ARGS__))
#define raft_log(me, ...) (raft_log_node(me, RAFT_NODE_ID_NONE, __VA_ARGS__))
void raft_randomize_election_timeout(raft_server_t* me_)
{
......@@ -116,7 +116,7 @@ raft_server_t* raft_new_with_log(const raft_log_impl_t *log_impl, void *log_arg)
me->voting_cfg_change_log_idx = -1;
raft_set_state((raft_server_t*)me, RAFT_STATE_FOLLOWER);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
me->snapshot_in_progress = 0;
raft_set_snapshot_metadata((raft_server_t*)me, 0, 0);
......@@ -155,7 +155,7 @@ void raft_clear(raft_server_t* me_)
raft_randomize_election_timeout(me_);
me->voting_cfg_change_log_idx = -1;
raft_set_state((raft_server_t*)me, RAFT_STATE_FOLLOWER);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
me->commit_idx = 0;
me->last_applied_idx = 0;
me->num_nodes = 0;
......@@ -167,7 +167,7 @@ raft_node_t* raft_add_node_internal(raft_server_t* me_, raft_entry_t *ety, void*
{
raft_server_private_t* me = (raft_server_private_t*)me_;
if (id == RAFT_UNKNOWN_NODE_ID)
if (id == RAFT_NODE_ID_NONE)
return NULL;
/* set to voting if node already exists */
......@@ -253,7 +253,7 @@ void raft_remove_node(raft_server_t* me_, raft_node_t* node)
me->num_nodes--;
if (me->leader_id == raft_node_get_id(node)) {
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
}
raft_node_free(node);
......@@ -365,7 +365,11 @@ int raft_election_start(raft_server_t* me_)
me->election_timeout_rand, me->timeout_elapsed, me->current_term,
raft_get_current_idx(me_));
return raft_become_candidate(me_);
me->leader_id = RAFT_NODE_ID_NONE;
me->timeout_elapsed = 0;
raft_randomize_election_timeout(me_);
return raft_become_precandidate(me_);
}
int raft_become_leader(raft_server_t* me_)
......@@ -414,6 +418,32 @@ int raft_become_leader(raft_server_t* me_)
return 0;
}
int raft_become_precandidate(raft_server_t* me_)
{
raft_server_private_t* me = (raft_server_private_t*)me_;
raft_log(me_,
"becoming pre-candidate, next term : %ld", me->current_term + 1);
if (me->cb.notify_state_event)
me->cb.notify_state_event(me_, me->udata, RAFT_STATE_PRECANDIDATE);
for (int i = 0; i < me->num_nodes; i++)
raft_node_vote_for_me(me->nodes[i], 0);
raft_set_state(me_, RAFT_STATE_PRECANDIDATE);
for (int i = 0; i < me->num_nodes; i++)
{
raft_node_t* node = me->nodes[i];
if (me->node != node && raft_node_is_voting(node))
raft_send_requestvote(me_, node);
}
return 0;
}
int raft_become_candidate(raft_server_t* me_)
{
raft_server_private_t* me = (raft_server_private_t*)me_;
......@@ -432,12 +462,9 @@ int raft_become_candidate(raft_server_t* me_)
if (raft_node_is_voting(me->node))
raft_vote(me_, me->node);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
raft_set_state(me_, RAFT_STATE_CANDIDATE);
raft_randomize_election_timeout(me_);
me->timeout_elapsed = 0;
for (i = 0; i < me->num_nodes; i++)
{
raft_node_t* node = me->nodes[i];
......@@ -621,7 +648,7 @@ int raft_recv_appendentries_response(raft_server_t* me_,
if (0 != e)
return e;
raft_become_follower(me_);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
return 0;
}
else if (me->current_term != r->term)
......@@ -882,39 +909,6 @@ out:
return e;
}
int raft_already_voted(raft_server_t* me_)
{
return ((raft_server_private_t*)me_)->voted_for != -1;
}
static int raft_should_grant_vote(raft_server_t* me_, msg_requestvote_t* vr)
{
if (vr->term < raft_get_current_term(me_))
return 0;
/* TODO: if voted for is candidate return 1 (if below checks pass) */
if (raft_already_voted(me_))
return 0;
/* Below we check if log is more up-to-date... */
raft_index_t current_idx = raft_get_current_idx(me_);
/* Our log is definitely not more up-to-date if it's empty! */
if (0 == current_idx)
return 1;
raft_term_t ety_term = raft_get_last_log_term(me_);
if (ety_term < vr->last_log_term)
return 1;
if (vr->last_log_term == ety_term && current_idx <= vr->last_log_idx)
return 1;
return 0;
}
int raft_recv_requestvote(raft_server_t* me_,
raft_node_t* node,
msg_requestvote_t* vr,
......@@ -923,46 +917,68 @@ int raft_recv_requestvote(raft_server_t* me_,
raft_server_private_t* me = (raft_server_private_t*)me_;
int e = 0;
r->prevote = vr->prevote;
r->request_term = vr->term;
r->vote_granted = 0;
if (!node)
node = raft_get_node(me_, vr->candidate_id);
/* Reject request if we have a leader */
if (me->leader_id != RAFT_UNKNOWN_NODE_ID &&
if (me->leader_id != RAFT_NODE_ID_NONE &&
me->leader_id != vr->candidate_id &&
me->timeout_elapsed < me->election_timeout) {
goto done;
}
if (raft_get_current_term(me_) < vr->term)
/* Update the term only if this is not a prevote request */
if (!vr->prevote && raft_get_current_term(me_) < vr->term)
{
e = raft_set_current_term(me_, vr->term);
if (0 != e) {
goto done;
}
raft_become_follower(me_);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
}
if (me->current_term > vr->term) {
goto done;
}
if (me->current_term == vr->term &&
(me->voted_for != -1 && me->voted_for != vr->candidate_id)) {
goto done;
}
/* Below we check if log is more up-to-date... */
raft_index_t current_idx = raft_get_current_idx(me_);
raft_term_t ety_term = raft_get_last_log_term(me_);
if (vr->last_log_term < ety_term ||
(vr->last_log_term == ety_term && vr->last_log_idx < current_idx)) {
goto done;
}
if (raft_should_grant_vote(me_, vr))
r->vote_granted = 1;
if (!vr->prevote)
{
/* It shouldn't be possible for a leader or candidate to grant a vote
* Both states would have voted for themselves */
assert(!(raft_is_leader(me_) || raft_is_candidate(me_)));
e = raft_vote_for_nodeid(me_, vr->candidate_id);
if (0 == e)
r->vote_granted = 1;
if (0 != e)
r->vote_granted = 0;
/* must be in an election. */
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
me->timeout_elapsed = 0;
}
done:
raft_log_node(me_, vr->candidate_id, "node requested vote: %d replying: %s",
raft_log_node(me_, vr->candidate_id, "node requested vote: %d, t:%ld, pv:%d replying: %s",
vr->candidate_id,
vr->term,
vr->prevote,
r->vote_granted == 1 ? "granted" :
r->vote_granted == 0 ? "not granted" : "unknown");
......@@ -985,34 +1001,45 @@ int raft_recv_requestvote_response(raft_server_t* me_,
raft_server_private_t* me = (raft_server_private_t*)me_;
raft_log_node(me_, raft_node_get_id(node),
"node responded to requestvote status:%s ct:%ld rt:%ld",
r->vote_granted == 1 ? "granted" :
r->vote_granted == 0 ? "not granted" : "unknown",
me->current_term,
r->term);
if (!raft_is_candidate(me_) || raft_get_current_term(me_) > r->term)
{
return 0;
}
if (raft_get_current_term(me_) < r->term)
"node responded to requestvote status:%s pv:%d rt:%ld ct:%ld rt:%ld",
r->vote_granted == 1 ? "granted" :
r->vote_granted == 0 ? "not granted" : "unknown",
r->prevote,
r->request_term,
me->current_term,
r->term);
if (r->term > me->current_term)
{
int e = raft_set_current_term(me_, r->term);
if (0 != e)
return e;
raft_become_follower(me_);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
return 0;
}
if (r->prevote) {
/* Validate prevote is not stale */
if (!raft_is_precandidate(me_) || r->request_term != me->current_term + 1)
return 0;
} else {
/* Validate reqvote is not stale */
if (!raft_is_candidate(me_) || r->request_term != me->current_term)
return 0;
}
if (r->vote_granted)
{
if (node)
raft_node_vote_for_me(node, 1);
int votes = raft_get_nvotes_for_me(me_);
if (raft_votes_is_majority(raft_get_num_voting_nodes(me_), votes)) {
int e = raft_become_leader(me_);
int nodes = raft_get_num_voting_nodes(me_);
if (raft_votes_is_majority(nodes, votes)) {
int e = raft_is_precandidate(me_) ? raft_become_candidate(me_) :
raft_become_leader(me_);
if (0 != e)
return e;
}
......@@ -1094,7 +1121,17 @@ int raft_send_requestvote(raft_server_t* me_, raft_node_t* node)
raft_node_id_t id = raft_node_get_id(node);
raft_log_node(me_, id, "sending requestvote to: %d", id);
rv.term = me->current_term;
if (raft_is_precandidate(me_))
{
rv.prevote = 1;
rv.term = me->current_term + 1;
}
else
{
rv.prevote = 0;
rv.term = me->current_term;
}
rv.last_log_idx = raft_get_current_idx(me_);
rv.last_log_term = raft_get_last_log_term(me_);
rv.candidate_id = raft_get_nodeid(me_);
......@@ -1319,7 +1356,7 @@ int raft_get_nvotes_for_me(raft_server_t* me_)
}
}
if (me->voted_for == raft_get_nodeid(me_))
if (raft_node_is_voting(me->node))
votes += 1;
return votes;
......@@ -1559,7 +1596,7 @@ int raft_begin_load_snapshot(
}
raft_set_state((raft_server_t*)me, RAFT_STATE_FOLLOWER);
me->leader_id = RAFT_UNKNOWN_NODE_ID;
me->leader_id = RAFT_NODE_ID_NONE;
me->log_impl->reset(me->log, last_included_index + 1, last_included_term);
......
......@@ -204,6 +204,11 @@ int raft_is_leader(raft_server_t* me_)
return raft_get_state(me_) == RAFT_STATE_LEADER;
}
int raft_is_precandidate(raft_server_t* me_)
{
return raft_get_state(me_) == RAFT_STATE_PRECANDIDATE;
}
int raft_is_candidate(raft_server_t* me_)
{
return raft_get_state(me_) == RAFT_STATE_CANDIDATE;
......
......@@ -213,13 +213,23 @@ void TestRaft_server_remove_node(CuTest * tc)
CuAssertTrue(tc, NULL == raft_get_node(r, 9));
}
void TestRaft_election_start_increments_term(CuTest * tc)
void TestRaft_election_start_does_not_increment_term(CuTest * tc)
{
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_set_callbacks(r, &generic_funcs, NULL);
raft_set_current_term(r, 1);
raft_election_start(r);
CuAssertTrue(tc, 1 == raft_get_current_term(r));
}
void TestRaft_election_become_candidate_increments_term(CuTest * tc)
{
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_set_callbacks(r, &generic_funcs, NULL);
raft_set_current_term(r, 1);
raft_become_candidate(r);
CuAssertTrue(tc, 2 == raft_get_current_term(r));
}
......@@ -632,7 +642,7 @@ void TestRaft_server_recv_requestvote_response_dont_increase_votes_for_me_when_n
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 1);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
msg_requestvote_response_t rvr;
memset(&rvr, 0, sizeof(msg_requestvote_response_t));
......@@ -640,7 +650,7 @@ void TestRaft_server_recv_requestvote_response_dont_increase_votes_for_me_when_n
rvr.vote_granted = 0;
int e = raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr);
CuAssertIntEquals(tc, 0, e);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
}
void TestRaft_server_recv_requestvote_response_dont_increase_votes_for_me_when_term_is_not_equal(
......@@ -658,14 +668,14 @@ void TestRaft_server_recv_requestvote_response_dont_increase_votes_for_me_when_t
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 3);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
msg_requestvote_response_t rvr;
memset(&rvr, 0, sizeof(msg_requestvote_response_t));
rvr.term = 2;
rvr.vote_granted = 1;
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
}
void TestRaft_server_recv_requestvote_response_increase_votes_for_me(
......@@ -685,7 +695,7 @@ void TestRaft_server_recv_requestvote_response_increase_votes_for_me(
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 1);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
CuAssertIntEquals(tc, 1, raft_get_current_term(r));
raft_become_candidate(r);
......@@ -694,6 +704,7 @@ void TestRaft_server_recv_requestvote_response_increase_votes_for_me(
msg_requestvote_response_t rvr;
memset(&rvr, 0, sizeof(msg_requestvote_response_t));
rvr.request_term = 2;
rvr.term = 2;
rvr.vote_granted = 1;
int e = raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr);
......@@ -717,7 +728,7 @@ void TestRaft_server_recv_requestvote_response_must_be_candidate_to_receive(
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 1);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
raft_become_leader(r);
......@@ -726,7 +737,7 @@ void TestRaft_server_recv_requestvote_response_must_be_candidate_to_receive(
rvr.term = 1;
rvr.vote_granted = 1;
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr);
CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r));
CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r));
}
/* Reply false if term < currentTerm (§5.1) */
......@@ -934,7 +945,7 @@ void TestRaft_server_recv_requestvote_dont_grant_vote_if_we_didnt_vote_for_this_
msg_requestvote_t rv = {};
rv.term = 1;
rv.candidate_id = 1;
rv.candidate_id = 2;
rv.last_log_idx = 1;
rv.last_log_term = 1;
msg_requestvote_response_t rvr;
......@@ -987,6 +998,73 @@ void TestRaft_server_recv_requestvote_ignore_if_master_is_fresh(CuTest * tc)
CuAssertTrue(tc, 1 == rvr.vote_granted);
}
void TestRaft_server_recv_prevote_ignore_if_candidate(CuTest * tc)
{
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 1);
raft_set_election_timeout(r, 1000);
raft_become_candidate(r);
msg_requestvote_response_t rv = {
.term = 1,
.request_term = 1,
.prevote = 1,
};
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rv);
CuAssertTrue(tc, raft_is_candidate(r));
CuAssertTrue(tc, raft_get_nvotes_for_me(r) == 1);
}
void TestRaft_server_recv_reqvote_ignore_if_not_candidate(CuTest * tc)
{
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 1);
raft_set_election_timeout(r, 1000);
raft_become_precandidate(r);
msg_requestvote_response_t rv = {
.term = 1,
.request_term = 1
};
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rv);
CuAssertTrue(tc, raft_is_precandidate(r));
CuAssertTrue(tc, raft_get_nvotes_for_me(r) == 1);
}
void TestRaft_server_recv_reqvote_always_update_term(CuTest * tc)
{
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_current_term(r, 1);
raft_set_election_timeout(r, 1000);
raft_become_precandidate(r);
msg_requestvote_response_t rv = {
.term = 3,
.request_term = 3,
};
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rv);
CuAssertTrue(tc, raft_is_follower(r));
CuAssertTrue(tc, raft_get_current_term(r) == 3);
}
void TestRaft_follower_becomes_follower_is_follower(CuTest * tc)
{
void *r = raft_new();
......@@ -1686,7 +1764,7 @@ void TestRaft_follower_recv_appendentries_failure_includes_current_idx(
CuAssertIntEquals(tc, 2, aer.current_idx);
}
void TestRaft_follower_becomes_candidate_when_election_timeout_occurs(
void TestRaft_follower_becomes_precandidate_when_election_timeout_occurs(
CuTest * tc)
{
raft_cbs_t funcs = {
......@@ -1708,7 +1786,7 @@ void TestRaft_follower_becomes_candidate_when_election_timeout_occurs(
raft_periodic(r, max_election_timeout(1000) + 1);
/* is a candidate now */
CuAssertTrue(tc, 1 == raft_is_candidate(r));
CuAssertTrue(tc, 1 == raft_is_precandidate(r));
}
/* Candidate 5.2 */
......@@ -2024,11 +2102,6 @@ void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(
void *r = raft_new();
raft_set_callbacks(r, &funcs, NULL);
msg_requestvote_response_t vr;
memset(&vr, 0, sizeof(msg_requestvote_response_t));
vr.term = 0;
vr.vote_granted = 1;
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_election_timeout(r, 1000);
......@@ -2037,13 +2110,30 @@ void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(
raft_become_candidate(r);
CuAssertTrue(tc, 1 == raft_get_current_term(r));
/* clock over (ie. max election timeout + 1), causing new election */
/* clock over (ie. max election timeout + 1), does not increment term */
raft_periodic(r, max_election_timeout(1000) + 1);
CuAssertTrue(tc, 2 == raft_get_current_term(r));
CuAssertTrue(tc, 1 == raft_get_current_term(r));
CuAssertIntEquals(tc, RAFT_STATE_PRECANDIDATE, raft_get_state(r));
msg_requestvote_response_t vr0 = {
.prevote = 1,
.request_term = raft_get_current_term(r) + 1,
.term = 0,
.vote_granted = 1
};
/* receiving this vote gives the server majority */
raft_recv_requestvote_response(r, raft_get_node(r, 2), &vr0);
CuAssertIntEquals(tc, RAFT_STATE_CANDIDATE, raft_get_state(r));
msg_requestvote_response_t vr1 = {
.request_term = 2,
.term = 2,
.vote_granted = 1
};
/* receiving this vote gives the server majority */
// raft_recv_requestvote_response(r,1,&vr);
// CuAssertTrue(tc, 1 == raft_is_leader(r));
raft_recv_requestvote_response(r, raft_get_node(r, 2), &vr1);
CuAssertIntEquals(tc, RAFT_STATE_LEADER, raft_get_state(r));
}
/* Candidate 5.2 */
......@@ -2075,6 +2165,7 @@ void TestRaft_candidate_receives_majority_of_votes_becomes_leader(CuTest * tc)
/* a vote for us */
memset(&vr, 0, sizeof(msg_requestvote_response_t));
vr.request_term = 1;
vr.term = 1;
vr.vote_granted = 1;
/* get one vote */
......@@ -2170,6 +2261,7 @@ void TestRaft_candidate_recv_requestvote_response_becomes_follower_if_current_te
msg_requestvote_response_t rvr;
memset(&rvr, 0, sizeof(msg_requestvote_response_t));
rvr.request_term = 2;
rvr.term = 2;
rvr.vote_granted = 0;
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr);
......@@ -3571,17 +3663,30 @@ void TestRaft_leader_recv_requestvote_responds_without_granting(CuTest * tc)
raft_election_start(r);
msg_requestvote_response_t rvr;
memset(&rvr, 0, sizeof(msg_requestvote_response_t));
rvr.term = 1;
rvr.vote_granted = 1;
msg_requestvote_response_t rvr = {
.prevote = 1,
.request_term = raft_get_current_term(r) + 1,
.term = 0,
.vote_granted = 1
};
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr);
CuAssertTrue(tc, 1 == raft_is_candidate(r));
msg_requestvote_response_t rvr1 = {
.request_term = 1,
.term = 1,
.vote_granted = 1
};
raft_recv_requestvote_response(r, raft_get_node(r, 2), &rvr1);
CuAssertTrue(tc, 1 == raft_is_leader(r));
/* receive request vote from node 3 */
msg_requestvote_t rv;
memset(&rv, 0, sizeof(msg_requestvote_t));
rv.term = 1;
msg_requestvote_t rv = {
.term = 1
};
raft_recv_requestvote(r, raft_get_node(r, 3), &rv, &rvr);
CuAssertTrue(tc, 0 == rvr.vote_granted);
}
......@@ -4133,8 +4238,10 @@ void TestRaft_removed_node_starts_election(CuTest * tc)
raft_become_follower(r);
raft_set_election_timeout(r, 1000);
raft_periodic(r, 2000);
raft_become_candidate(r);
msg_requestvote_response_t reqresp = {
.request_term = 2,
.vote_granted = 1,
.term = 2
};
......@@ -4163,7 +4270,8 @@ int main(void)
SUITE_ADD_TEST(suite, TestRaft_server_add_non_voting_node_with_already_existing_id_is_not_allowed);
SUITE_ADD_TEST(suite, TestRaft_server_add_non_voting_node_with_already_existing_voting_id_is_not_allowed);
SUITE_ADD_TEST(suite, TestRaft_server_remove_node);
SUITE_ADD_TEST(suite, TestRaft_election_start_increments_term);
SUITE_ADD_TEST(suite, TestRaft_election_start_does_not_increment_term);
SUITE_ADD_TEST(suite, TestRaft_election_become_candidate_increments_term);
SUITE_ADD_TEST(suite, TestRaft_set_state);
SUITE_ADD_TEST(suite, TestRaft_server_starts_as_follower);
SUITE_ADD_TEST(suite, TestRaft_server_starts_with_election_timeout_of_1000ms);
......@@ -4200,6 +4308,9 @@ int main(void)
SUITE_ADD_TEST(suite, TestRaft_server_recv_requestvote_depends_on_candidate_id);
SUITE_ADD_TEST(suite, TestRaft_server_recv_requestvote_dont_grant_vote_if_we_didnt_vote_for_this_candidate);
SUITE_ADD_TEST(suite, TestRaft_server_recv_requestvote_ignore_if_master_is_fresh);
SUITE_ADD_TEST(suite, TestRaft_server_recv_prevote_ignore_if_candidate);
SUITE_ADD_TEST(suite, TestRaft_server_recv_reqvote_ignore_if_not_candidate);
SUITE_ADD_TEST(suite, TestRaft_server_recv_reqvote_always_update_term);
SUITE_ADD_TEST(suite, TestRaft_follower_becomes_follower_is_follower);
SUITE_ADD_TEST(suite, TestRaft_follower_becomes_follower_does_not_clear_voted_for);
SUITE_ADD_TEST(suite, TestRaft_follower_recv_appendentries_reply_false_if_term_less_than_currentterm);
......@@ -4217,7 +4328,7 @@ int main(void)
SUITE_ADD_TEST(suite, TestRaft_follower_recv_appendentries_set_commitidx_to_prevLogIdx);
SUITE_ADD_TEST(suite, TestRaft_follower_recv_appendentries_set_commitidx_to_LeaderCommit);
SUITE_ADD_TEST(suite, TestRaft_follower_recv_appendentries_failure_includes_current_idx);
SUITE_ADD_TEST(suite, TestRaft_follower_becomes_candidate_when_election_timeout_occurs);
SUITE_ADD_TEST(suite, TestRaft_follower_becomes_precandidate_when_election_timeout_occurs);
SUITE_ADD_TEST(suite, TestRaft_follower_dont_grant_vote_if_candidate_has_a_less_complete_log);
SUITE_ADD_TEST(suite, TestRaft_follower_recv_appendentries_heartbeat_does_not_overwrite_logs);
SUITE_ADD_TEST(suite, TestRaft_follower_recv_appendentries_does_not_deleted_commited_entries);
......
......@@ -101,6 +101,8 @@ def state2str(state):
return colorama.Fore.GREEN + 'leader' + colorama.Style.RESET_ALL
elif state == lib.RAFT_STATE_CANDIDATE:
return 'candidate'
elif state == lib.RAFT_STATE_PRECANDIDATE:
return 'pre-candidate'
elif state == lib.RAFT_STATE_FOLLOWER:
return 'follower'
else:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment