From 50637964edb7ed6e6c99ef606c1cec88071ed439 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 19 Mar 2024 12:25:31 +0800 Subject: [PATCH 1/4] raft: add fmt::formatter for error classes before this change, we rely on the default-generated fmt::formatter created from operator<<, but fmt v10 dropped the default-generated formatter. in this change, we define formatter for classes derived from `raft::error`. since {fmt} v10 defines the formatter for all classes derived from `std::exception`, the definition is provided only when the tree is compiled with {fmt} < 10. Refs #13245 Signed-off-by: Kefu Chai --- raft/raft.hh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/raft/raft.hh b/raft/raft.hh index 452f0142d0..0884f6f292 100644 --- a/raft/raft.hh +++ b/raft/raft.hh @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include @@ -814,6 +815,16 @@ public: } // namespace raft +#if FMT_VERSION < 100000 +// fmt v10 introduced formatter for std::exception +template T> +struct fmt::formatter : fmt::formatter { + auto format(const T& e, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", e.what()); + } +}; +#endif + template <> struct fmt::formatter : fmt::formatter { auto format(const raft::server_address&, fmt::format_context& ctx) const -> decltype(ctx.out()); From 97b203b1af2dae6e606f14a724b208c31044a7aa Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 19 Mar 2024 12:28:03 +0800 Subject: [PATCH 2/4] test: randomized_nemesis_test: add fmt::formatter for seastar::timed_out_error before this change, we rely on the default-generated fmt::formatter created from operator<<, but fmt v10 dropped the default-generated formatter. in this change, we define formatter for `seastar::timed_out_error`, which will be used by the `fmt::formatter` for `std::variant<...>`. Refs #13245 Signed-off-by: Kefu Chai --- test/raft/randomized_nemesis_test.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/raft/randomized_nemesis_test.cc b/test/raft/randomized_nemesis_test.cc index f67c93be01..3aaa50ce43 100644 --- a/test/raft/randomized_nemesis_test.cc +++ b/test/raft/randomized_nemesis_test.cc @@ -48,6 +48,16 @@ std::ostream& operator<<(std::ostream& os, const std::variant& v) { } // namespace std +#if FMT_VERSION < 100000 +// fmt v10 introduced formatter for std::exception +template <> +struct fmt::formatter : fmt::formatter { + auto format(const seastar::timed_out_error& e, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", e.what()); + } +}; +#endif + using namespace seastar; using namespace std::chrono_literals; From 72899f573eb35c2fbac5f512f31a6a75fc67706c Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 19 Mar 2024 11:33:31 +0800 Subject: [PATCH 3/4] test: randomized_nemesis_test: add fmt::formatter for some types before this change, we rely on the default-generated fmt::formatter created from operator<<, but fmt v10 dropped the default-generated formatter. in this change, we define formatters for * raft_call * raft_read * network_majority_grudge * reconfiguration * stop_crash * operation::thread_id * append_seq * append_entry * AppendReg::append * AppendReg::ret and drop their operator<<:s. in which, * `operator<<` for `std::monostate` and `std::variant` are dropped. as we are now using their counterparts in {fmt}. * stop_crash::result_type 's `fmt::formatter` is not added, as we cannot define a partial specialization of `fmt::formatter` for a nested class for a template class. we will tackle this struct in another change. Refs #13245 Signed-off-by: Kefu Chai --- test/raft/randomized_nemesis_test.cc | 91 +++++++++++++++++----------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/test/raft/randomized_nemesis_test.cc b/test/raft/randomized_nemesis_test.cc index 3aaa50ce43..90cb4b01eb 100644 --- a/test/raft/randomized_nemesis_test.cc +++ b/test/raft/randomized_nemesis_test.cc @@ -36,13 +36,12 @@ namespace std { -std::ostream& operator<<(std::ostream& os, const std::monostate&) { - return os << ""; -} - +// fmt::formatter requires that the none of Ts... has +// fallback formatter, so we cannot use it before ditching operator<< of +// all element types. template std::ostream& operator<<(std::ostream& os, const std::variant& v) { - std::visit([&os] (auto& arg) { os << arg; }, v); + std::visit([&os] (auto& arg) { fmt::print(os, "{}", arg); }, v); return os; } @@ -2599,9 +2598,12 @@ struct raft_call { co_return res; } +}; - friend std::ostream& operator<<(std::ostream& os, const raft_call& c) { - return os << format("raft_call{{input:{},timeout:{}}}", c.input, c.timeout); +template +struct fmt::formatter> : fmt::formatter { + auto format(const raft_call& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "raft_call{{input:{}, timeout:{}}}", r.input, r.timeout); } }; @@ -2634,9 +2636,12 @@ struct raft_read { co_return result_type{read_id, std::move(res)}; } +}; - friend std::ostream& operator<<(std::ostream& os, const raft_read& r) { - return os << format("raft_read{{id:{}, timeout:{}}}", r.read_id, r.timeout); +template +struct fmt::formatter> : fmt::formatter { + auto format(const raft_read& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "raft_read{{id:{}, timeout:{}}}", r.read_id, r.timeout); } }; @@ -2706,8 +2711,13 @@ public: co_return std::monostate{}; } - friend std::ostream& operator<<(std::ostream& os, const network_majority_grudge& p) { - return os << format("network_majority_grudge{{duration:{}}}", p._duration); + friend fmt::formatter; +}; + +template +struct fmt::formatter> : fmt::formatter { + auto format(const network_majority_grudge& p, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "network_majority_grudge{{duration:{}}}", p._duration); } }; @@ -2832,9 +2842,12 @@ struct reconfiguration { return execute_reconfigure(s, ctx, std::move(nodes), members_end, voters_end); } } +}; - friend std::ostream& operator<<(std::ostream& os, const reconfiguration& r) { - return os << format("reconfiguration{{timeout:{}}}", r.timeout); +template +struct fmt::formatter>: fmt::formatter { + auto format(const reconfiguration& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "reconfiguration{{timeout:{}}}", r.timeout); } }; @@ -2873,22 +2886,23 @@ struct stop_crash { co_return result_type{}; } - friend std::ostream& operator<<(std::ostream& os, const stop_crash& c) { - return os << format("stop_crash{{delay:{}}}", c.restart_delay); - } - friend std::ostream& operator<<(std::ostream& os, const result_type&) { return os << ""; } }; -namespace operation { +template +struct fmt::formatter>: fmt::formatter { + auto format(const stop_crash& c, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "stop_crash{{delay:{}}}", c.restart_delay); + } +}; -std::ostream& operator<<(std::ostream& os, const thread_id& tid) { - return os << format("thread_id{{{}}}", tid.id); -} - -} // namespace operation +template <> struct fmt::formatter: fmt::formatter { + auto format(const operation::thread_id& tid, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "thread_id{{{}}}", tid.id); + } +}; // An immutable sequence of integers. class append_seq { @@ -2971,11 +2985,7 @@ public: return {{_seq, _end - 1, digest_remove(_digest, (*_seq)[_end - 1])}, (*_seq)[_end - 1]}; } - friend std::ostream& operator<<(std::ostream& os, const append_seq& s) { - // TODO: don't copy the elements - std::vector v{s._seq->begin(), s._seq->begin() + s._end}; - return os << format("seq({} _end {})", v, s._end); - } + friend fmt::formatter; private: append_seq(lw_shared_ptr> seq, size_t end, elem_t d) @@ -2997,6 +3007,15 @@ struct AppendReg { static thread_local const state_t init; }; +template <> struct fmt::formatter : fmt::formatter { + auto format(const append_seq& s, fmt::format_context& ctx) const { + // TODO: don't copy the elements + std::vector v{s._seq->begin(), s._seq->begin() + s._end}; + return fmt::format_to(ctx.out(), "seq({} _end {})", v, s._end); + } +}; + + thread_local const AppendReg::state_t AppendReg::init{{0}}; namespace ser { @@ -3187,13 +3206,17 @@ private: } }; -std::ostream& operator<<(std::ostream& os, const AppendReg::append& a) { - return os << format("append{{{}}}", a.x); -} +template <> struct fmt::formatter : fmt::formatter { + auto format(const AppendReg::append& a, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "append{{{}}}", a.x); + } +}; -std::ostream& operator<<(std::ostream& os, const AppendReg::ret& r) { - return os << format("ret{{{}, {}}}", r.x, r.prev); -} +template <> struct fmt::formatter : fmt::formatter { + auto format(const AppendReg::ret& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "ret{{{}, {}}}", r.x, r.prev); + } +}; SEASTAR_TEST_CASE(basic_generator_test) { using op_type = operation::invocable Date: Tue, 19 Mar 2024 10:34:08 +0800 Subject: [PATCH 4/4] test: raft: generator: add fmt::formatter:s before this change, we rely on the default-generated fmt::formatter created from operator<<, but fmt v10 dropped the default-generated formatter. in this change, we define formatters for * operation::either_of * operation::exceptional_result * operation::completion * operation::invocable and drop their operator<<:s. Refs #13245 Signed-off-by: Kefu Chai --- test/raft/generator.hh | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/test/raft/generator.hh b/test/raft/generator.hh index 5127b03106..cbfc2ebae0 100644 --- a/test/raft/generator.hh +++ b/test/raft/generator.hh @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include "utils/chunked_vector.hh" @@ -469,10 +471,6 @@ struct either_of { either_of(Op o) : op(std::move(o)) { static_assert(Executable>); } - - friend std::ostream& operator<<(std::ostream& os, const either_of& e) { - return os << e.op; - } }; } // namespace operation @@ -827,20 +825,34 @@ stagger_gen stagger( } // namespace generator -namespace operation { +template +struct fmt::formatter> : fmt::formatter { + auto format(operation::either_of& e, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", e.op); + } +}; template -std::ostream& operator<<(std::ostream& os, const exceptional_result& r) { - try { - std::rethrow_exception(r.eptr); - } catch (const std::exception& e) { - return os << format("exceptional{{i:{}, ex:{}}}", r.op, e); +struct fmt::formatter> : fmt::formatter { + auto format(const operation::exceptional_result& r, fmt::format_context& ctx) const { + try { + std::rethrow_exception(r.eptr); + } catch (const std::exception& e) { + return fmt::format_to(ctx.out(), "exceptional{{i:{}, ex:{}}}", r.op, e); + } } -} +}; template -std::ostream& operator<<(std::ostream& os, const completion& c) { - return os << format("c{{r:{}, t:{}, tid:{}}}", c.result, c.time, c.thread); -} +struct fmt::formatter> : fmt::formatter { + auto format(const operation::completion& c, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "c{{r:{}, t:{}, tid:{}}}", c.result, c.time, c.thread); + } +}; -} // namespace operation +template +struct fmt::formatter> : fmt::formatter { + auto format(const operation::invocable& op, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", static_cast(op)); + } +};