diff --git a/src/box/raft.c b/src/box/raft.c index 0b6c373e86d9369235f8954a761781af0ad0a3d7..9ee3b70057fd41d03d3426e79fb195f34e961113 100644 --- a/src/box/raft.c +++ b/src/box/raft.c @@ -178,6 +178,13 @@ raft_election_quorum(void) return MIN(replication_synchro_quorum, replicaset.registered_count); } +/** + * Wakeup the Raft worker fiber in order to do some async work. If the fiber + * does not exist yet, it is created. + */ +static void +raft_worker_wakeup(void); + /** Schedule broadcast of the complete Raft state to all the followers. */ static void raft_schedule_broadcast(void); @@ -670,10 +677,8 @@ raft_sm_pause_and_dump(void) if (raft.is_write_in_progress) return; ev_timer_stop(loop(), &raft.timer); + raft_worker_wakeup(); raft.is_write_in_progress = true; - if (raft.worker == NULL) - raft.worker = fiber_new("raft_worker", raft_worker_f); - fiber_wakeup(raft.worker); } static void @@ -988,21 +993,43 @@ raft_new_term(void) } static void -raft_schedule_broadcast(void) +raft_worker_wakeup(void) { - raft.is_broadcast_scheduled = true; + if (raft.worker == NULL) { + raft.worker = fiber_new("raft_worker", raft_worker_f); + if (raft.worker == NULL) { + /* + * XXX: should be handled properly, no need to panic. + * The issue though is that most of the Raft state + * machine functions are not supposed to fail, and also + * they usually wakeup the fiber when their work is + * finished. So it is too late to fail. On the other + * hand it looks not so good to create the fiber when + * Raft is initialized. Because then it will occupy + * memory even if Raft is not used. + */ + diag_log(); + panic("Could't create Raft worker fiber"); + return; + } + fiber_set_joinable(raft.worker, true); + } /* * Don't wake the fiber if it writes something. Otherwise it would be a - * spurious wakeup breaking the WAL write not adapted to this. + * spurious wakeup breaking the WAL write not adapted to this. Also + * don't wakeup the current fiber - it leads to undefined behaviour. */ - if (raft.is_write_in_progress) - return; - if (raft.worker == NULL) - raft.worker = fiber_new("raft_worker", raft_worker_f); - if (raft.worker != fiber()) + if (!raft.is_write_in_progress && fiber() != raft.worker) fiber_wakeup(raft.worker); } +static void +raft_schedule_broadcast(void) +{ + raft.is_broadcast_scheduled = true; + raft_worker_wakeup(); +} + void raft_init(void) {