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
Willemt Raft
Commits
29bf1bcf
Commit
29bf1bcf
authored
Jan 25, 2016
by
Willem Thiart
Browse files
raft_recv_entry won't accept 1 < voting changes
parent
8a7b07a0
Changes
4
Hide whitespace changes
Inline
Side-by-side
include/raft.h
View file @
29bf1bcf
...
...
@@ -180,6 +180,7 @@ typedef int (
);
/** Callback for detecting when non-voting nodes have obtained enough logs.
* This triggers only when there are no pending configuration changes.
* @param[in] raft The Raft server making this callback
* @param[in] user_data User data that is passed from Raft server
* @param[in] node The node */
...
...
@@ -635,4 +636,14 @@ void raft_apply_all(raft_server_t* me_);
* losing it's consensus guarantees. */
void
raft_become_leader
(
raft_server_t
*
me
);
/** Determine if entry is voting configuration change.
* @param[in] ety The entry to query.
* @return 1 if this is a voting configuration change. */
int
raft_entry_is_voting_cfg_change
(
raft_entry_t
*
ety
);
/** Determine if entry is configuration change.
* @param[in] ety The entry to query.
* @return 1 if this is a configuration change. */
int
raft_entry_is_cfg_change
(
raft_entry_t
*
ety
);
#endif
/* RAFT_H_ */
include/raft_private.h
View file @
29bf1bcf
...
...
@@ -56,6 +56,9 @@ typedef struct {
/* my node ID */
raft_node_t
*
node
;
/* the log which has a voting cfg change, otherwise -1 */
int
voting_cfg_change_log_idx
;
}
raft_server_private_t
;
void
raft_election_start
(
raft_server_t
*
me
);
...
...
src/raft_server.c
View file @
29bf1bcf
...
...
@@ -49,6 +49,7 @@ raft_server_t* raft_new()
me
->
request_timeout
=
200
;
me
->
election_timeout
=
1000
;
me
->
log
=
log_new
();
me
->
voting_cfg_change_log_idx
=
-
1
;
raft_set_state
((
raft_server_t
*
)
me
,
RAFT_STATE_FOLLOWER
);
me
->
current_leader
=
NULL
;
return
(
raft_server_t
*
)
me
;
...
...
@@ -220,6 +221,7 @@ int raft_recv_appendentries_response(raft_server_t* me_,
raft_node_set_match_idx
(
node
,
r
->
current_idx
);
if
(
!
raft_node_is_voting
(
node
)
&&
-
1
==
me
->
voting_cfg_change_log_idx
&&
raft_get_current_idx
(
me_
)
<=
r
->
current_idx
+
1
&&
me
->
cb
.
node_has_sufficient_logs
&&
0
==
raft_node_has_sufficient_logs
(
node
)
...
...
@@ -513,6 +515,11 @@ int raft_recv_entry(raft_server_t* me_,
raft_server_private_t
*
me
=
(
raft_server_private_t
*
)
me_
;
int
i
;
/* Only one voting cfg change at a time */
if
(
raft_entry_is_voting_cfg_change
(
e
))
if
(
-
1
!=
me
->
voting_cfg_change_log_idx
)
return
-
1
;
if
(
!
raft_is_leader
(
me_
))
return
-
1
;
...
...
@@ -546,6 +553,10 @@ int raft_recv_entry(raft_server_t* me_,
r
->
id
=
e
->
id
;
r
->
idx
=
raft_get_current_idx
(
me_
);
r
->
term
=
me
->
current_term
;
if
(
raft_entry_is_voting_cfg_change
(
e
))
me
->
voting_cfg_change_log_idx
=
raft_get_current_idx
(
me_
);
return
0
;
}
...
...
@@ -571,6 +582,10 @@ int raft_send_requestvote(raft_server_t* me_, raft_node_t* node)
int
raft_append_entry
(
raft_server_t
*
me_
,
raft_entry_t
*
ety
)
{
raft_server_private_t
*
me
=
(
raft_server_private_t
*
)
me_
;
if
(
raft_entry_is_voting_cfg_change
(
ety
))
me
->
voting_cfg_change_log_idx
=
raft_get_current_idx
(
me_
);
return
log_append_entry
(
me
->
log
,
ety
);
}
...
...
@@ -594,6 +609,11 @@ int raft_apply_entry(raft_server_t* me_)
me
->
last_applied_idx
++
;
if
(
me
->
cb
.
applylog
)
me
->
cb
.
applylog
(
me_
,
me
->
udata
,
e
);
/* voting cfg change is now complete */
if
(
log_idx
==
me
->
voting_cfg_change_log_idx
)
me
->
voting_cfg_change_log_idx
=
-
1
;
return
0
;
}
...
...
@@ -660,7 +680,7 @@ void raft_send_appendentries_all(raft_server_t* me_)
me
->
timeout_elapsed
=
0
;
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
]);
}
...
...
@@ -764,3 +784,17 @@ void raft_apply_all(raft_server_t* me_)
while
(
raft_get_last_applied_idx
(
me_
)
<
raft_get_commit_idx
(
me_
))
raft_apply_entry
(
me_
);
}
int
raft_entry_is_voting_cfg_change
(
raft_entry_t
*
ety
)
{
return
RAFT_LOGTYPE_ADD_NODE
==
ety
->
type
||
RAFT_LOGTYPE_REMOVE_NODE
==
ety
->
type
;
}
int
raft_entry_is_cfg_change
(
raft_entry_t
*
ety
)
{
return
(
RAFT_LOGTYPE_ADD_NODE
==
ety
->
type
||
RAFT_LOGTYPE_ADD_NONVOTING_NODE
==
ety
->
type
||
RAFT_LOGTYPE_REMOVE_NODE
==
ety
->
type
);
}
tests/test_server.c
View file @
29bf1bcf
...
...
@@ -384,6 +384,31 @@ void TestRaft_server_recv_entry_auto_commits_if_we_are_the_only_node(CuTest * tc
CuAssertTrue
(
tc
,
1
==
raft_get_commit_idx
(
r
));
}
void
TestRaft_server_recv_entry_fails_if_there_is_already_a_voting_change
(
CuTest
*
tc
)
{
void
*
r
=
raft_new
();
raft_add_node
(
r
,
NULL
,
1
,
1
);
raft_set_election_timeout
(
r
,
1000
);
raft_become_leader
(
r
);
CuAssertTrue
(
tc
,
0
==
raft_get_commit_idx
(
r
));
/* entry message */
msg_entry_t
ety
;
ety
.
type
=
RAFT_LOGTYPE_ADD_NODE
;
ety
.
id
=
1
;
ety
.
data
.
buf
=
"entry"
;
ety
.
data
.
len
=
strlen
(
"entry"
);
/* receive entry */
msg_entry_response_t
cr
;
CuAssertTrue
(
tc
,
0
==
raft_recv_entry
(
r
,
&
ety
,
&
cr
));
CuAssertTrue
(
tc
,
1
==
raft_get_log_count
(
r
));
ety
.
id
=
2
;
CuAssertTrue
(
tc
,
-
1
==
raft_recv_entry
(
r
,
&
ety
,
&
cr
));
CuAssertTrue
(
tc
,
1
==
raft_get_commit_idx
(
r
));
}
void
TestRaft_server_cfg_sets_num_nodes
(
CuTest
*
tc
)
{
void
*
r
=
raft_new
();
...
...
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