diff --git a/changelogs/unreleased/gh-8169-raft-assert-on-wal-write.md b/changelogs/unreleased/gh-8169-raft-assert-on-wal-write.md new file mode 100644 index 0000000000000000000000000000000000000000..e7f8752804d51403444f0c4535a13501d5696600 --- /dev/null +++ b/changelogs/unreleased/gh-8169-raft-assert-on-wal-write.md @@ -0,0 +1,4 @@ +## bugfix/raft + +* Fixed an assertion failure in case an election candidate is reconfigured to a + voter during an ongoning WAL write (gh-8169). diff --git a/src/lib/raft/raft.c b/src/lib/raft/raft.c index 87ef5b7871bf241f19a381d4e419b0924a3e90c2..4dccc7aea2c5c0545db5f7d3562afa20cbd0104c 100644 --- a/src/lib/raft/raft.c +++ b/src/lib/raft/raft.c @@ -1163,9 +1163,11 @@ raft_stop_candidate(struct raft *raft) } else { /* * Leader is seen and node is waiting for its death. Do not stop - * the timer. + * the timer. If there is a write in progress the timer is + * stopped now, but will be re-started once the write completes. */ - assert(raft_ev_timer_is_active(&raft->timer)); + assert(raft_ev_timer_is_active(&raft->timer) || + raft->is_write_in_progress); } raft->state = RAFT_STATE_FOLLOWER; raft_schedule_broadcast(raft); diff --git a/test/unit/raft.c b/test/unit/raft.c index b63183e888151b9c1f28e5385e73822cbf35727f..923eac192cac5666c63fe685099b730afc850a89 100644 --- a/test/unit/raft.c +++ b/test/unit/raft.c @@ -2347,10 +2347,52 @@ raft_test_resign(void) raft_finish_test(); } +static void +raft_test_candidate_disable_during_wal_write(void) +{ + raft_start_test(2); + /* + * There was a false-positive assertion failure in a special case: the + * node has just received a is_leader notification and is currently + * writing it on disk. At the same time it is configured as voter + * (gh-8169). + */ + struct raft_node node; + raft_node_create(&node); + raft_node_cfg_is_candidate(&node, true); + raft_node_block(&node); + raft_node_send_leader(&node, 2, 2); + ok(raft_node_check_full_state( + &node, + RAFT_STATE_FOLLOWER /* State. */, + 2 /* Leader. */, + 1 /* Term. */, + 0 /* Vote. */, + 2 /* Volatile term. */, + 0 /* Volatile vote. */, + "{}" /* Vclock. */ + ), "Leader is seen, but wal write is in progress"); + raft_node_cfg_is_candidate(&node, false); + raft_node_unblock(&node); + ok(raft_node_check_full_state( + &node, + RAFT_STATE_FOLLOWER /* State. */, + 2 /* Leader. */, + 2 /* Term. */, + 0 /* Vote. */, + 2 /* Volatile term. */, + 0 /* Volatile vote. */, + "{0: 1}" /* Vclock. */ + ), "State is persisted"); + + raft_node_destroy(&node); + raft_finish_test(); +} + static int main_f(va_list ap) { - raft_start_test(19); + raft_start_test(20); (void) ap; fakeev_init(); @@ -2374,6 +2416,7 @@ main_f(va_list ap) raft_test_split_vote(); raft_test_pre_vote(); raft_test_resign(); + raft_test_candidate_disable_during_wal_write(); fakeev_free();