Commit 1aee978a authored by Willem Thiart's avatar Willem Thiart
Browse files

Add membership changes

parent 1c6cb689
...@@ -560,6 +560,11 @@ int raft_get_my_id(raft_server_t* me); ...@@ -560,6 +560,11 @@ int raft_get_my_id(raft_server_t* me);
* @param[in] node The server to vote for */ * @param[in] node The server to vote for */
void raft_vote(raft_server_t* me_, raft_node_t* node); void raft_vote(raft_server_t* me_, raft_node_t* node);
/** Vote for a server.
* This should be used to reload persistent state, ie. the voted-for field.
* @param[in] nodeid The server to vote for by nodeid */
void raft_vote_for_nodeid(raft_server_t* me_, const int nodeid);
/** Set the current term. /** Set the current term.
* This should be used to reload persistent state, ie. the current_term field. * This should be used to reload persistent state, ie. the current_term field.
* @param[in] term The new current term */ * @param[in] term The new current term */
......
...@@ -21,7 +21,7 @@ typedef struct { ...@@ -21,7 +21,7 @@ typedef struct {
/* The candidate the server voted for in its current term, /* The candidate the server voted for in its current term,
* or Nil if it hasn't voted for any. */ * or Nil if it hasn't voted for any. */
raft_node_t* voted_for; int voted_for;
/* the log which is replicated */ /* the log which is replicated */
void* log; void* log;
......
...@@ -103,7 +103,6 @@ void raft_node_set_voting(raft_node_t* me_, int voting) ...@@ -103,7 +103,6 @@ void raft_node_set_voting(raft_node_t* me_, int voting)
me->flags |= RAFT_NODE_VOTING; me->flags |= RAFT_NODE_VOTING;
else else
me->flags &= ~RAFT_NODE_VOTING; me->flags &= ~RAFT_NODE_VOTING;
} }
int raft_node_is_voting(raft_node_t* me_) int raft_node_is_voting(raft_node_t* me_)
......
...@@ -44,7 +44,7 @@ raft_server_t* raft_new() ...@@ -44,7 +44,7 @@ raft_server_t* raft_new()
if (!me) if (!me)
return NULL; return NULL;
me->current_term = 0; me->current_term = 0;
me->voted_for = NULL; me->voted_for = -1;
me->timeout_elapsed = 0; me->timeout_elapsed = 0;
me->request_timeout = 200; me->request_timeout = 200;
me->election_timeout = 1000; me->election_timeout = 1000;
...@@ -144,9 +144,7 @@ int raft_periodic(raft_server_t* me_, int msec_since_last_period) ...@@ -144,9 +144,7 @@ int raft_periodic(raft_server_t* me_, int msec_since_last_period)
} }
else if (me->election_timeout <= me->timeout_elapsed) else if (me->election_timeout <= me->timeout_elapsed)
{ {
if (1 == me->num_nodes) if (1 < me->num_nodes)
raft_become_leader(me_);
else
raft_election_start(me_); raft_election_start(me_);
} }
...@@ -270,9 +268,6 @@ int raft_recv_appendentries( ...@@ -270,9 +268,6 @@ int raft_recv_appendentries(
{ {
raft_server_private_t* me = (raft_server_private_t*)me_; raft_server_private_t* me = (raft_server_private_t*)me_;
assert(node);
assert(node != me->node);
me->timeout_elapsed = 0; me->timeout_elapsed = 0;
if (0 < ae->n_entries) if (0 < ae->n_entries)
...@@ -285,11 +280,13 @@ int raft_recv_appendentries( ...@@ -285,11 +280,13 @@ int raft_recv_appendentries(
ae->prev_log_term, ae->prev_log_term,
ae->n_entries); ae->n_entries);
printf("%p %p\n", node, raft_get_current_leader_node(me_));
r->term = me->current_term; r->term = me->current_term;
if (raft_is_candidate(me_) && me->current_term == ae->term) if (raft_is_candidate(me_) && me->current_term == ae->term)
{ {
me->voted_for = NULL; me->voted_for = -1;
raft_become_follower(me_); raft_become_follower(me_);
} }
else if (me->current_term < ae->term) else if (me->current_term < ae->term)
...@@ -402,7 +399,7 @@ static int __should_grant_vote(raft_server_private_t* me, msg_requestvote_t* vr) ...@@ -402,7 +399,7 @@ static int __should_grant_vote(raft_server_private_t* me, msg_requestvote_t* vr)
/* TODO: if voted for is candiate return 1 (if below checks pass) */ /* TODO: if voted for is candiate return 1 (if below checks pass) */
/* we've already voted */ /* we've already voted */
if (me->voted_for) if (0 < me->voted_for)
return 0; return 0;
int current_idx = raft_get_current_idx((void*)me); int current_idx = raft_get_current_idx((void*)me);
...@@ -427,9 +424,6 @@ int raft_recv_requestvote(raft_server_t* me_, ...@@ -427,9 +424,6 @@ int raft_recv_requestvote(raft_server_t* me_,
{ {
raft_server_private_t* me = (raft_server_private_t*)me_; raft_server_private_t* me = (raft_server_private_t*)me_;
assert(node);
assert(node != me->node);
if (raft_get_current_term(me_) < vr->term) if (raft_get_current_term(me_) < vr->term)
{ {
raft_set_current_term(me_, vr->term); raft_set_current_term(me_, vr->term);
...@@ -442,7 +436,7 @@ int raft_recv_requestvote(raft_server_t* me_, ...@@ -442,7 +436,7 @@ int raft_recv_requestvote(raft_server_t* me_,
* Both states would have voted for themselves */ * Both states would have voted for themselves */
assert(!(raft_is_leader(me_) || raft_is_candidate(me_))); assert(!(raft_is_leader(me_) || raft_is_candidate(me_)));
raft_vote(me_, node); raft_vote_for_nodeid(me_, vr->candidate_id);
r->vote_granted = 1; r->vote_granted = 1;
/* there must be in an election. */ /* there must be in an election. */
...@@ -662,7 +656,7 @@ void raft_send_appendentries_all(raft_server_t* me_) ...@@ -662,7 +656,7 @@ void raft_send_appendentries_all(raft_server_t* me_)
me->timeout_elapsed = 0; me->timeout_elapsed = 0;
for (i = 0; i < me->num_nodes; i++) for (i = 0; i < me->num_nodes; i++)
if (me->node != me->nodes[i] && raft_node_is_voting(me->nodes[i])) if (me->node != me->nodes[i])
raft_send_appendentries(me_, me->nodes[i]); raft_send_appendentries(me_, me->nodes[i]);
} }
...@@ -702,21 +696,24 @@ int raft_get_nvotes_for_me(raft_server_t* me_) ...@@ -702,21 +696,24 @@ int raft_get_nvotes_for_me(raft_server_t* me_)
if (raft_node_has_vote_for_me(me->nodes[i])) if (raft_node_has_vote_for_me(me->nodes[i]))
votes += 1; votes += 1;
if (me->voted_for == me->node) if (me->voted_for == raft_get_nodeid(me_))
votes += 1; votes += 1;
return votes; return votes;
} }
void raft_vote(raft_server_t* me_, raft_node_t* node) void raft_vote_for_nodeid(raft_server_t* me_, const int nodeid)
{ {
raft_server_private_t* me = (raft_server_private_t*)me_; raft_server_private_t* me = (raft_server_private_t*)me_;
assert(!me->voted_for || node != me->voted_for); me->voted_for = nodeid;
me->voted_for = node;
if (me->cb.persist_vote) if (me->cb.persist_vote)
me->cb.persist_vote(me_, me->udata, raft_node_get_id(node)); me->cb.persist_vote(me_, me->udata, nodeid);
}
void raft_vote(raft_server_t* me_, raft_node_t* node)
{
raft_vote_for_nodeid(me_, node ? raft_node_get_id(node) : -1);
} }
int raft_msg_entry_response_committed(raft_server_t* me_, int raft_msg_entry_response_committed(raft_server_t* me_,
......
...@@ -66,9 +66,7 @@ int raft_get_log_count(raft_server_t* me_) ...@@ -66,9 +66,7 @@ int raft_get_log_count(raft_server_t* me_)
int raft_get_voted_for(raft_server_t* me_) int raft_get_voted_for(raft_server_t* me_)
{ {
raft_server_private_t* me = (raft_server_private_t*)me_; raft_server_private_t* me = (raft_server_private_t*)me_;
if (me->voted_for) return me->voted_for;
return raft_node_get_id(me->voted_for);
return -1;
} }
void raft_set_current_term(raft_server_t* me_, const int term) void raft_set_current_term(raft_server_t* me_, const int term)
...@@ -77,7 +75,7 @@ void raft_set_current_term(raft_server_t* me_, const int term) ...@@ -77,7 +75,7 @@ void raft_set_current_term(raft_server_t* me_, const int term)
if (me->current_term < term) if (me->current_term < term)
{ {
me->current_term = term; me->current_term = term;
me->voted_for = NULL; me->voted_for = -1;
if (me->cb.persist_term) if (me->cb.persist_term)
me->cb.persist_term(me_, me->udata, term); me->cb.persist_term(me_, me->udata, term);
} }
......
...@@ -581,6 +581,7 @@ void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than ...@@ -581,6 +581,7 @@ void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than
/* current term is less than term */ /* current term is less than term */
msg_requestvote_t rv; msg_requestvote_t rv;
memset(&rv, 0, sizeof(msg_requestvote_t)); memset(&rv, 0, sizeof(msg_requestvote_t));
rv.candidate_id = 2;
rv.term = 2; rv.term = 2;
rv.last_log_idx = 1; rv.last_log_idx = 1;
msg_requestvote_response_t rvr; msg_requestvote_response_t rvr;
...@@ -590,6 +591,30 @@ void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than ...@@ -590,6 +591,30 @@ void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than
CuAssertIntEquals(tc, 2, raft_get_voted_for(r)); CuAssertIntEquals(tc, 2, raft_get_voted_for(r));
} }
void TestRaft_server_recv_requestvote_depends_on_candidate_id(
CuTest * tc
)
{
void *r = raft_new();
raft_add_node(r, NULL, 1, 1);
raft_add_node(r, NULL, 2, 0);
raft_become_candidate(r);
raft_set_current_term(r, 1);
CuAssertIntEquals(tc, 1, raft_get_voted_for(r));
/* current term is less than term */
msg_requestvote_t rv;
memset(&rv, 0, sizeof(msg_requestvote_t));
rv.candidate_id = 3;
rv.term = 2;
rv.last_log_idx = 1;
msg_requestvote_response_t rvr;
raft_recv_requestvote(r, NULL, &rv, &rvr);
CuAssertIntEquals(tc, 1, raft_is_follower(r));
CuAssertIntEquals(tc, 2, raft_get_current_term(r));
CuAssertIntEquals(tc, 3, raft_get_voted_for(r));
}
/* If votedFor is null or candidateId, and candidate's log is at /* If votedFor is null or candidateId, and candidate's log is at
* least as up-to-date as local log, grant vote (5.2, 5.4) */ * least as up-to-date as local log, grant vote (5.2, 5.4) */
void TestRaft_server_dont_grant_vote_if_we_didnt_vote_for_this_candidate( void TestRaft_server_dont_grant_vote_if_we_didnt_vote_for_this_candidate(
......
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