Skip to content

Commit

Permalink
utils: phased_barrier: Make advance_and_await() have strong exception…
Browse files Browse the repository at this point in the history
… guarantees

Currently, when advance_and_await() fails to allocate the new gate
object, it will throw bad_alloc and leave the phased_barrier object in
an invalid state. Calling advance_and_await() again on it will result
in undefined behavior (typically SIGSEGV) beacuse _gate will be
disengaged.

One place affected by this is table::seal_active_memtable(), which
calls _flush_barrier.advance_and_await(). If this throws, subsequent
flush attempts will SIGSEGV.

This patch rearranges the code so that advance_and_await() has strong
exception guarantees.
Message-Id: <1542645562-20932-1-git-send-email-tgrabiec@scylladb.com>

Fixes #3931.

(cherry picked from commit 57e25fa)
  • Loading branch information
tgrabiec authored and avikivity committed Nov 21, 2018
1 parent e5f9dae commit de00d7f
Showing 1 changed file with 3 additions and 2 deletions.
5 changes: 3 additions & 2 deletions utils/phased_barrier.hh
Expand Up @@ -68,10 +68,11 @@ public:

// Starts a new phase and waits for all operations started in any of the earlier phases.
// It is fine to start multiple awaits in parallel.
// Strong exception guarantees.
future<> advance_and_await() {
auto new_gate = make_lw_shared<gate>();
++_phase;
auto old_gate = std::move(_gate);
_gate = make_lw_shared<gate>();
auto old_gate = std::exchange(_gate, std::move(new_gate));
return old_gate->close().then([old_gate, op = start()] {});
}

Expand Down

0 comments on commit de00d7f

Please sign in to comment.