Commit 14a4e6a2 authored by Li Wei's avatar Li Wei Committed by Willem Thiart
Browse files

DAOS-279 server: Discard current_leader when term changes



When a leader learns of a newer term and steps down, it should discard
current_leader. Otherwise, a client request may be rejected with
RAFT_ERR_NOT_LEADER and a hint pointing to this replica itself!

For simplicity, this patche follows the Raft paper to discard
current_leader whenever current_term changes. And, when receiving an AE
with an up-to-date term, a server always updates current_leader, as this
information is absolute, even if the previous entry doesn't match.

This patch also fixes a test that has previously been failing due to
incorrect node IDs.
Signed-off-by: default avatarLi Wei <wei.g.li@intel.com>
parent 3096ecd7
......@@ -51,7 +51,7 @@ typedef struct {
int election_timeout;
int request_timeout;
/* what this node thinks is the node ID of the current leader, or -1 if
/* what this node thinks is the node ID of the current leader, or NULL if
* there isn't a known current leader. */
raft_node_t* current_leader;
......
......@@ -238,6 +238,7 @@ int raft_recv_appendentries_response(raft_server_t* me_,
{
raft_set_current_term(me_, r->term);
raft_become_follower(me_);
me->current_leader = NULL;
return 0;
}
else if (me->current_term != r->term)
......@@ -353,6 +354,9 @@ int raft_recv_appendentries(
goto fail_with_current_idx;
}
/* update current leader because ae->term is up to date */
me->current_leader = node;
/* Not the first appendentries we've received */
/* NOTE: the log starts at 1 */
if (0 < ae->prev_log_idx)
......@@ -434,9 +438,6 @@ int raft_recv_appendentries(
raft_set_commit_idx(me_, min(last_log_idx, ae->leader_commit));
}
/* update current leader because we accepted appendentries from it */
me->current_leader = node;
r->success = 1;
r->first_idx = ae->prev_log_idx + 1;
return 0;
......@@ -503,6 +504,7 @@ int raft_recv_requestvote(raft_server_t* me_,
{
raft_set_current_term(me_, vr->term);
raft_become_follower(me_);
me->current_leader = NULL;
}
if (__should_grant_vote(me, vr))
......@@ -571,6 +573,7 @@ int raft_recv_requestvote_response(raft_server_t* me_,
{
raft_set_current_term(me_, r->term);
raft_become_follower(me_);
me->current_leader = NULL;
return 0;
}
else if (raft_get_current_term(me_) != r->term)
......
......@@ -3373,6 +3373,38 @@ void TestRaft_leader_recv_appendentries_response_drop_message_if_term_is_old(
CuAssertTrue(tc, 1 == raft_node_get_next_idx(p));
}
void TestRaft_leader_recv_appendentries_response_steps_down_if_term_is_newer(
CuTest * tc)
{
raft_cbs_t funcs = {
.send_appendentries = sender_appendentries,
.log = NULL
};
void *sender = sender_new(NULL);
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_set_callbacks(r, &funcs, sender);
/* I'm the leader */
raft_set_state(r, RAFT_STATE_LEADER);
raft_set_current_term(r, 2);
raft_node_t* p = raft_get_node(r, 2);
CuAssertTrue(tc, 1 == raft_node_get_next_idx(p));
/* receive NEW mock failed responses */
msg_appendentries_response_t aer;
aer.term = 3;
aer.success = 0;
aer.current_idx = 2;
aer.first_idx = 0;
raft_recv_appendentries_response(r, raft_get_node(r, 2), &aer);
CuAssertTrue(tc, 1 == raft_is_follower(r));
CuAssertTrue(tc, -1 == raft_get_current_leader(r));
}
void TestRaft_leader_recv_appendentries_steps_down_if_newer(
CuTest * tc)
{
......@@ -3391,7 +3423,7 @@ void TestRaft_leader_recv_appendentries_steps_down_if_newer(
raft_set_state(r, RAFT_STATE_LEADER);
raft_set_current_term(r, 5);
/* check that node 0 considers itself the leader */
/* check that node 1 considers itself the leader */
CuAssertTrue(tc, 1 == raft_is_leader(r));
CuAssertTrue(tc, 1 == raft_get_current_leader(r));
......@@ -3401,10 +3433,10 @@ void TestRaft_leader_recv_appendentries_steps_down_if_newer(
ae.prev_log_term = 5;
raft_recv_appendentries(r, raft_get_node(r, 2), &ae, &aer);
/* after more recent appendentries from node 1, node 0 should
* consider node 1 the leader. */
/* after more recent appendentries from node 2, node 1 should
* consider node 2 the leader. */
CuAssertTrue(tc, 1 == raft_is_follower(r));
CuAssertTrue(tc, 1 == raft_get_current_leader(r));
CuAssertTrue(tc, 2 == raft_get_current_leader(r));
}
void TestRaft_leader_recv_appendentries_steps_down_if_newer_term(
......
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