diff --git a/db/commitlog/commitlog.cc b/db/commitlog/commitlog.cc index b059a8d72c..6b59aa0536 100644 --- a/db/commitlog/commitlog.cc +++ b/db/commitlog/commitlog.cc @@ -1614,6 +1614,8 @@ future db::commitlog::segment_manager: } future db::commitlog::segment_manager::new_segment() { + gate::holder g(_gate); + if (_shutdown) { co_return coroutine::make_exception(std::runtime_error("Commitlog has been shut down. Cannot add data")); } @@ -1648,20 +1650,23 @@ future db::commitlog::segment_manager: co_return _segments.back(); } - if (_segment_allocating) { - co_await _segment_allocating->get_future(timeout); - continue; + // #9896 - we don't want to issue a new_segment call until + // the old one has terminated with either result or exception. + // Do all waiting through the shared_future + if (!_segment_allocating) { + _segment_allocating.emplace(new_segment().discard_result()); } - - promise<> p; - _segment_allocating.emplace(p.get_future()); - auto finally = defer([&] () noexcept { _segment_allocating = std::nullopt; }); try { - gate::holder g(_gate); - auto s = co_await with_timeout(timeout, new_segment()); - p.set_value(); - } catch (...) { - p.set_exception(std::current_exception()); + co_await _segment_allocating->get_future(timeout); + // once we've managed to get a result, any of us, the + // shared_future should be released. + _segment_allocating = std::nullopt; + } catch (timed_out_error&) { + throw; // not thrown by new_segment. Just no result yet. + } catch (...) { + // once we've managed to get a result, any of us, the + // shared_future should be released. + _segment_allocating = std::nullopt; throw; } }