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
b1a110d3
Unverified
Commit
b1a110d3
authored
Mar 30, 2022
by
Ozan Tezcan
Committed by
GitHub
Mar 30, 2022
Browse files
Add automatic leader transfer target selection (#95)
parent
8ee3f264
Changes
3
Hide whitespace changes
Inline
Side-by-side
include/raft.h
View file @
b1a110d3
...
@@ -1517,10 +1517,14 @@ int raft_queue_read_request(raft_server_t* me, raft_read_request_callback_f cb,
...
@@ -1517,10 +1517,14 @@ int raft_queue_read_request(raft_server_t* me, raft_read_request_callback_f cb,
*/
*/
void
raft_process_read_queue
(
raft_server_t
*
me
);
void
raft_process_read_queue
(
raft_server_t
*
me
);
/*
/** Invoke a leadership transfer to targeted node
* invoke a leadership transfer to targeted node
*
* node_id = targeted node
* @param[in] node_id targeted node, RAFT_NODE_ID_NONE for automatic target
* timeout = timeout in ms before this transfer is aborted. if 0, use default election timeout
* selection. Node with the most entries will be selected.
* @param[in] timeout timeout in ms before this transfer is aborted.
* if 0, use default election timeout
* @return an error if leadership transfer is already in progress or
* the targeted node_id is unknown
*/
*/
int
raft_transfer_leader
(
raft_server_t
*
me
,
raft_node_id_t
node_id
,
long
timeout
);
int
raft_transfer_leader
(
raft_server_t
*
me
,
raft_node_id_t
node_id
,
long
timeout
);
...
...
src/raft_server.c
View file @
b1a110d3
...
@@ -1951,11 +1951,6 @@ void raft_process_read_queue(raft_server_t* me)
...
@@ -1951,11 +1951,6 @@ void raft_process_read_queue(raft_server_t* me)
}
}
}
}
/* invoke a leadership transfer
* node_id = targeted node we are transferring to
* timeout = how long this should be allowed to take in milliseconds, as calculated by calls to raft_periodic
* return an error if leadership transfer is already in progress of the targeted node_id is unknown
*/
int
raft_transfer_leader
(
raft_server_t
*
me
,
raft_node_id_t
node_id
,
long
timeout
)
int
raft_transfer_leader
(
raft_server_t
*
me
,
raft_node_id_t
node_id
,
long
timeout
)
{
{
if
(
me
->
state
!=
RAFT_STATE_LEADER
)
{
if
(
me
->
state
!=
RAFT_STATE_LEADER
)
{
...
@@ -1966,7 +1961,26 @@ int raft_transfer_leader(raft_server_t* me, raft_node_id_t node_id, long timeout
...
@@ -1966,7 +1961,26 @@ int raft_transfer_leader(raft_server_t* me, raft_node_id_t node_id, long timeout
return
RAFT_ERR_LEADER_TRANSFER_IN_PROGRESS
;
return
RAFT_ERR_LEADER_TRANSFER_IN_PROGRESS
;
}
}
raft_node_t
*
target
=
raft_get_node
(
me
,
node_id
);
raft_node_t
*
target
=
NULL
;
if
(
node_id
!=
RAFT_NODE_ID_NONE
)
{
target
=
raft_get_node
(
me
,
node_id
);
}
else
{
/* Find the most up-to-date node. As we need to replicate less entries
* to this node, it is the best candidate for leader transfer. */
raft_index_t
max
=
0
;
for
(
int
i
=
0
;
i
<
raft_get_num_nodes
(
me
);
i
++
)
{
raft_node_t
*
node
=
raft_get_node_from_idx
(
me
,
i
);
raft_index_t
match
=
raft_node_get_match_idx
(
node
);
if
(
node
!=
me
->
node
&&
match
>
max
)
{
target
=
node
;
max
=
match
;
}
}
}
if
(
target
==
NULL
||
target
==
me
->
node
)
{
if
(
target
==
NULL
||
target
==
me
->
node
)
{
return
RAFT_ERR_INVALID_NODEID
;
return
RAFT_ERR_INVALID_NODEID
;
}
}
...
@@ -1977,7 +1991,7 @@ int raft_transfer_leader(raft_server_t* me, raft_node_id_t node_id, long timeout
...
@@ -1977,7 +1991,7 @@ int raft_transfer_leader(raft_server_t* me, raft_node_id_t node_id, long timeout
me
->
sent_timeout_now
=
1
;
me
->
sent_timeout_now
=
1
;
}
}
me
->
node_transferring_leader_to
=
node_id
;
me
->
node_transferring_leader_to
=
raft_node_get_id
(
target
)
;
me
->
transfer_leader_time
=
(
timeout
!=
0
)
?
timeout
:
me
->
election_timeout
;
me
->
transfer_leader_time
=
(
timeout
!=
0
)
?
timeout
:
me
->
election_timeout
;
return
0
;
return
0
;
...
...
tests/test_server.c
View file @
b1a110d3
...
@@ -4541,6 +4541,33 @@ void Test_transfer_leader_not_leader(CuTest *tc)
...
@@ -4541,6 +4541,33 @@ void Test_transfer_leader_not_leader(CuTest *tc)
CuAssertIntEquals(tc, RAFT_ERR_NOT_LEADER, ret);
CuAssertIntEquals(tc, RAFT_ERR_NOT_LEADER, ret);
}
}
void Test_transfer_automatic(CuTest *tc)
{
raft_leader_transfer_e state = RAFT_LEADER_TRANSFER_TIMEOUT;
raft_cbs_t funcs = {
.notify_transfer_event = cb_notify_transfer_event,
};
raft_server_t *r = raft_new();
raft_set_callbacks(r, &funcs, &state);
raft_node_t *n1 = raft_add_node(r, NULL, 100, 1);
raft_set_state(r, RAFT_STATE_LEADER);
raft_node_t *n2 = raft_add_node(r, NULL, 2, 0);
raft_node_set_match_idx(n2, 5);
raft_node_t *n3 = raft_add_node(r, NULL, 3, 0);
raft_node_set_match_idx(n3, 8);
raft_node_t *n4 = raft_add_node(r, NULL, 3, 0);
raft_node_set_match_idx(n3, 6);
int ret = raft_transfer_leader(r, RAFT_NODE_ID_NONE, 0);
CuAssertIntEquals(tc, 0, ret);
CuAssertIntEquals(tc, 3, raft_get_transfer_leader(r));
}
int main(void)
int main(void)
{
{
CuString *output = CuStringNew();
CuString *output = CuStringNew();
...
@@ -4684,6 +4711,7 @@ int main(void)
...
@@ -4684,6 +4711,7 @@ int main(void)
SUITE_ADD_TEST(suite, Test_transfer_leader_success);
SUITE_ADD_TEST(suite, Test_transfer_leader_success);
SUITE_ADD_TEST(suite, Test_transfer_leader_unexpected);
SUITE_ADD_TEST(suite, Test_transfer_leader_unexpected);
SUITE_ADD_TEST(suite, Test_transfer_leader_not_leader);
SUITE_ADD_TEST(suite, Test_transfer_leader_not_leader);
SUITE_ADD_TEST(suite, Test_transfer_automatic);
CuSuiteRun(suite);
CuSuiteRun(suite);
CuSuiteDetails(suite, output);
CuSuiteDetails(suite, output);
printf("%s\n", output->buffer);
printf("%s\n", output->buffer);
...
...
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