Unverified Commit b1a110d3 authored by Ozan Tezcan's avatar Ozan Tezcan Committed by GitHub
Browse files

Add automatic leader transfer target selection (#95)

parent 8ee3f264
...@@ -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);
......
...@@ -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;
......
...@@ -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);
......
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