Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
RedisLabs Raft
Commits
73a3a856
Unverified
Commit
73a3a856
authored
Sep 14, 2021
by
Ozan Tezcan
Committed by
GitHub
Sep 14, 2021
Browse files
Prevote implementation (#52)
* prevote implementation
parent
bdd0797f
Changes
6
Hide whitespace changes
Inline
Side-by-side
include/raft.h
View file @
73a3a856
...
...
@@ -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.
...
...
include/raft_private.h
View file @
73a3a856
...
...
@@ -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
);
...
...
src/raft_server.c
View file @
73a3a856
...
...
@@ -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
);
...
...
src/raft_server_properties.c
View file @
73a3a856
...
...
@@ -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
;
...
...
tests/test_server.c
View file @
73a3a856
...
...
@@ -213,13 +213,23 @@ void TestRaft_server_remove_node(CuTest * tc)
CuAssertTrue
(
tc
,
NULL
==
raft_get_node
(
r
,
9
));
}
void
TestRaft_election_start_increment
s
_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_
pre
candidate_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_
pre
candidate
(
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);
//
CuAssert
True(tc, 1 == raft_is_leader
(r));
raft_recv_requestvote_response
(
r
,
raft_get_node
(
r
,
2
),
&
vr
1
);
CuAssert
IntEquals
(
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_
pre
candidate_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
);
...
...
tests/virtraft2.py
View file @
73a3a856
...
...
@@ -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
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment