瀏覽代碼

Fix a race condition when killing the election timer.

The kill() method tells the election timer to stop by notifying a
condvar that the timer blocks on. If the election timer is not blocked
on the condvar at that time, it might not get the signal, and goes
into sleep indefinitely right after that (`timeout = None`).

The potential solutions are
1) Change the `None` timeout to a reasonably long period.
2) Check the `keep_running` before going to sleep.
3) Add a new field to the timer to denote "we are stopped", and check
that field before making any changes.

3) requires a lot of changes. 1) risks wasting CPU cycles when the
current instance is elected. Thus we chose 2). The drawback is that
it looks less elegant.
Jing Yang 5 年之前
父節點
當前提交
cb7e82a666
共有 1 個文件被更改,包括 6 次插入0 次删除
  1. 6 0
      src/lib.rs

+ 6 - 0
src/lib.rs

@@ -333,6 +333,12 @@ impl Raft {
                         cancel_handle.take().map(|c| c.send(()));
                     }
                 }
+                // check the running signal before sleeping. We are holding the
+                // timer lock, so no one can change it. The kill() method will
+                // not be able to notify this thread before `wait` is called.
+                if !this.keep_running.load(Ordering::SeqCst) {
+                    break;
+                }
                 should_run = match deadline {
                     Some(timeout) => loop {
                         let ret =