From f035313b164ec60c72ac13c7c4cbcc387e1b8e27 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 26 Nov 2021 15:29:57 +0300 Subject: [PATCH] generic_server: Gentle iterator Add the ability to iterate over the list of connections in a "gentle" manner, i.e. -- preempting the loop when required. Signed-off-by: Pavel Emelyanov --- generic_server.cc | 17 +++++++++++++++++ generic_server.hh | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/generic_server.cc b/generic_server.cc index 15b33bf192..e7198e1002 100644 --- a/generic_server.cc +++ b/generic_server.cc @@ -11,6 +11,7 @@ #include "to_string.hh" #include +#include #include namespace generic_server { @@ -30,10 +31,26 @@ connection::~connection() { --_server._current_connections; server::connections_list_t::iterator iter = _server._connections_list.iterator_to(*this); + for (auto&& gi : _server._gentle_iterators) { + if (gi.iter == iter) { + gi.iter++; + } + } _server._connections_list.erase(iter); _server.maybe_stop(); } +future<> server::for_each_gently(noncopyable_function fn) { + _gentle_iterators.emplace_front(*this); + std::list::iterator gi = _gentle_iterators.begin(); + return seastar::do_until([ gi ] { return gi->iter == gi->end; }, + [ gi, fn = std::move(fn) ] { + fn(*(gi->iter++)); + return make_ready_future<>(); + } + ).finally([ this, gi ] { _gentle_iterators.erase(gi); }); +} + static bool is_broken_pipe_or_connection_reset(std::exception_ptr ep) { try { std::rethrow_exception(ep); diff --git a/generic_server.hh b/generic_server.hh index 3d922b1c0c..fa06ec29e0 100644 --- a/generic_server.hh +++ b/generic_server.hh @@ -82,6 +82,13 @@ protected: future<> _stopped = _all_connections_stopped.get_future(); using connections_list_t = boost::intrusive::list; connections_list_t _connections_list; + struct gentle_iterator { + connections_list_t::const_iterator iter, end; + gentle_iterator(const server& s) : iter(s._connections_list.begin()), end(s._connections_list.end()) {} + gentle_iterator(const gentle_iterator&) = delete; + gentle_iterator(gentle_iterator&&) = delete; + }; + std::list _gentle_iterators; std::vector _listeners; public: @@ -102,6 +109,8 @@ protected: virtual future<> unadvertise_connection(shared_ptr conn); + future<> for_each_gently(noncopyable_function); + void maybe_stop(); };