Commit 75b01044 authored by Willem Thiart's avatar Willem Thiart
Browse files

Fixed partitions created by rogue leaders

Thanks to @ar104 for helping me with the fix!
parent f563e205
......@@ -126,7 +126,6 @@ void raft_become_follower(raft_server_t* me_)
{
__log(me_, "becoming follower");
raft_set_state(me_, RAFT_STATE_FOLLOWER);
raft_vote(me_, -1);
}
int raft_periodic(raft_server_t* me_, int msec_since_last_period)
......@@ -171,13 +170,20 @@ int raft_recv_appendentries_response(raft_server_t* me_,
node, r->success == 1 ? "success" : "fail", r->current_idx,
r->first_idx);
// TODO: should force invalid leaders to stepdown
if (!raft_is_leader(me_))
return -1;
raft_node_t* p = raft_get_node(me_, node);
/* If response contains term T > currentTerm: set currentTerm = T
and convert to follower (§5.3) */
if (me->current_term < r->term)
{
raft_set_current_term(me_, r->term);
raft_become_follower(me_);
return 0;
}
if (0 == r->success)
{
/* If AppendEntries fails because of log inconsistency:
......@@ -350,7 +356,10 @@ int raft_recv_requestvote(raft_server_t* me_, int node, msg_requestvote_t* vr,
raft_server_private_t* me = (raft_server_private_t*)me_;
if (raft_get_current_term(me_) < vr->term)
{
raft_set_current_term(me_, vr->term);
raft_become_follower(me_);
}
if (__should_grant_vote(me, vr))
{
......@@ -430,7 +439,8 @@ int raft_recv_entry(raft_server_t* me_, int node, msg_entry_t* e,
/* Only send new entries.
* Don't send the entry to peers who are behind, to prevent them from
* becomming congested. */
if (me->nodeid != i) {
if (me->nodeid != i)
{
int next_idx = raft_node_get_next_idx(raft_get_node(me_, i));
int last_log_idx = raft_get_current_idx(me_);
if (next_idx == last_log_idx)
......
......@@ -71,9 +71,13 @@ int raft_get_voted_for(raft_server_t* me_)
void raft_set_current_term(raft_server_t* me_, const int term)
{
raft_server_private_t* me = (raft_server_private_t*)me_;
me->current_term = term;
if (me->cb.persist_term)
me->cb.persist_term(me_, me->udata, term);
if (me->current_term < term)
{
me->current_term = term;
me->voted_for = -1;
if (me->cb.persist_term)
me->cb.persist_term(me_, me->udata, term);
}
}
int raft_get_current_term(raft_server_t* me_)
......
......@@ -511,6 +511,7 @@ void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than
raft_add_node(r, (void*)2, 0);
raft_become_candidate(r);
raft_set_current_term(r, 1);
CuAssertIntEquals(tc, 0, raft_get_voted_for(r));
/* current term is less than term */
msg_requestvote_t rv;
......@@ -519,7 +520,9 @@ void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than
rv.last_log_idx = 1;
msg_requestvote_response_t rvr;
raft_recv_requestvote(r, 1, &rv, &rvr);
CuAssertTrue(tc, 1 == raft_is_follower(r));
CuAssertIntEquals(tc, 1, raft_is_follower(r));
CuAssertIntEquals(tc, 2, raft_get_current_term(r));
CuAssertIntEquals(tc, 1, raft_get_voted_for(r));
}
/* If votedFor is null or candidateId, and candidate's log is at
......@@ -552,13 +555,13 @@ void TestRaft_follower_becomes_follower_is_follower(CuTest * tc)
CuAssertTrue(tc, raft_is_follower(r));
}
void TestRaft_follower_becomes_follower_clears_voted_for(CuTest * tc)
void TestRaft_follower_becomes_follower_does_not_clear_voted_for(CuTest * tc)
{
void *r = raft_new();
raft_vote(r, 1);
CuAssertTrue(tc, 1 == raft_get_voted_for(r));
raft_become_follower(r);
CuAssertTrue(tc, -1 == raft_get_voted_for(r));
CuAssertTrue(tc, 1 == raft_get_voted_for(r));
}
/* 5.1 */
......@@ -1219,8 +1222,10 @@ void TestRaft_candidate_recv_appendentries_frm_leader_results_in_follower(
raft_add_node(r, (void*)2, 0);
raft_set_state(r, RAFT_STATE_CANDIDATE);
raft_vote(r, 0);
CuAssertTrue(tc, 0 == raft_is_follower(r));
CuAssertTrue(tc, -1 == raft_get_current_leader(r));
CuAssertTrue(tc, 0 == raft_get_current_term(r));
/* receive recent appendentries */
msg_appendentries_t ae;
......@@ -1232,6 +1237,8 @@ void TestRaft_candidate_recv_appendentries_frm_leader_results_in_follower(
CuAssertTrue(tc, 1 == raft_is_follower(r));
/* after accepting a leader, it's available as the last known leader */
CuAssertTrue(tc, 1 == raft_get_current_leader(r));
CuAssertTrue(tc, 1 == raft_get_current_term(r));
CuAssertTrue(tc, -1 == raft_get_voted_for(r));
}
/* Candidate 5.2 */
......@@ -1662,16 +1669,16 @@ void TestRaft_leader_recv_appendentries_response_increase_commit_idx_when_majori
raft_send_appendentries(r, 0);
raft_send_appendentries(r, 1);
/* receive mock success responses */
aer.term = 5;
aer.term = 1;
aer.success = 1;
aer.current_idx = 2;
aer.first_idx = 2;
raft_recv_appendentries_response(r, 0, &aer);
raft_recv_appendentries_response(r, 1, &aer);
/* leader will now have majority followers who have appended this log */
CuAssertTrue(tc, 2 == raft_get_commit_idx(r));
CuAssertIntEquals(tc, 2, raft_get_commit_idx(r));
raft_periodic(r, 1);
CuAssertTrue(tc, 2 == raft_get_last_applied_idx(r));
CuAssertIntEquals(tc, 2, raft_get_last_applied_idx(r));
}
void TestRaft_leader_recv_appendentries_response_retry_only_if_leader(CuTest * tc)
......
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