diff --git a/CMakeLists.txt b/CMakeLists.txt index b8b6980..9cef8df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,14 @@ set(source_files src/binsrv/event/generic_post_header_fwd.hpp src/binsrv/event/generic_post_header.hpp + src/binsrv/event/protocol_traits_fwd.hpp + src/binsrv/event/protocol_traits.hpp + src/binsrv/event/protocol_traits.cpp + + src/binsrv/event/reader_context_fwd.hpp + src/binsrv/event/reader_context.hpp + src/binsrv/event/reader_context.cpp + src/binsrv/event/rotate_body_impl_fwd.hpp src/binsrv/event/rotate_body_impl.hpp src/binsrv/event/rotate_body_impl.cpp diff --git a/src/app.cpp b/src/app.cpp index f46c7cd..ab1382b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -20,6 +20,7 @@ #include "binsrv/event/code_type.hpp" #include "binsrv/event/event.hpp" +#include "binsrv/event/reader_context.hpp" #include "easymysql/binlog.hpp" #include "easymysql/connection.hpp" @@ -220,8 +221,8 @@ int main(int argc, char *argv[]) { static constexpr std::byte expected_event_packet_prefix{'\0'}; util::const_byte_span portion; - binsrv::event::optional_format_description_post_header fde_post_header{}; - binsrv::event::optional_format_description_body fde_body{}; + + binsrv::event::reader_context context{}; while (!(portion = binlog.fetch()).empty()) { if (portion[0] != expected_event_packet_prefix) { @@ -233,24 +234,19 @@ int main(int argc, char *argv[]) { "fetched " + std::to_string(std::size(portion)) + "-byte(s) event from binlog"); - const binsrv::event::event generic_event{portion, fde_post_header, - fde_body}; + const binsrv::event::event current_event{context, portion}; - log_event_common_header(*logger, generic_event.get_common_header()); - if (generic_event.get_common_header().get_type_code() == + log_event_common_header(*logger, current_event.get_common_header()); + if (current_event.get_common_header().get_type_code() == binsrv::event::code_type::format_description) { - const auto &local_fde_post_header = - std::get>( - generic_event.get_post_header()); - const auto &local_fde_body = std::get>( - generic_event.get_body()); + const auto &local_fde_post_header = current_event.get_post_header< + binsrv::event::code_type::format_description>(); + const auto &local_fde_body = + current_event + .get_body(); log_format_description_event(*logger, local_fde_post_header, local_fde_body); - fde_post_header = local_fde_post_header; - fde_body = local_fde_body; } log_span_dump(*logger, portion); } diff --git a/src/binsrv/event/common_header.hpp b/src/binsrv/event/common_header.hpp index 2e9a1d6..4b4ccdf 100644 --- a/src/binsrv/event/common_header.hpp +++ b/src/binsrv/event/common_header.hpp @@ -10,6 +10,7 @@ #include "binsrv/event/code_type_fwd.hpp" #include "binsrv/event/flag_type_fwd.hpp" +#include "binsrv/event/protocol_traits_fwd.hpp" #include "util/byte_span_fwd.hpp" @@ -17,7 +18,7 @@ namespace binsrv::event { class [[nodiscard]] common_header { public: - static constexpr std::size_t size_in_bytes{19U}; + static constexpr std::size_t size_in_bytes{default_common_header_length}; explicit common_header(util::const_byte_span portion); diff --git a/src/binsrv/event/event.cpp b/src/binsrv/event/event.cpp index 20e238c..3b32c0d 100644 --- a/src/binsrv/event/event.cpp +++ b/src/binsrv/event/event.cpp @@ -13,6 +13,8 @@ #include "binsrv/event/flag_type.hpp" #include "binsrv/event/generic_body.hpp" #include "binsrv/event/generic_post_header.hpp" +#include "binsrv/event/protocol_traits_fwd.hpp" +#include "binsrv/event/reader_context.hpp" #include "util/byte_span_fwd.hpp" #include "util/conversion_helpers.hpp" @@ -20,9 +22,7 @@ namespace binsrv::event { -event::event(util::const_byte_span portion, - const optional_format_description_post_header &fde_post_header, - const optional_format_description_body &fde_body) +event::event(reader_context &context, util::const_byte_span portion) : common_header_{ [](util::const_byte_span event_portion) -> util::const_byte_span { if (std::size(event_portion) < @@ -42,13 +42,13 @@ event::event(util::const_byte_span portion, // format_description_events always include event footers with checksums footer_size = footer::size_in_bytes; } else { - if (fde_body) { + if (context.has_fde_processed()) { // if format_description event has already been encountered, we determine // whether there is a footer in the event from it - footer_size = - (fde_body->get_checksum_algorithm() == checksum_algorithm_type::crc32 - ? footer::size_in_bytes - : 0U); + footer_size = (context.get_current_checksum_algorithm() == + checksum_algorithm_type::crc32 + ? footer::size_in_bytes + : 0U); } else { // we get in this branch only for the very first artificial rotate event // and in this case it does not include the footer @@ -63,10 +63,10 @@ event::event(util::const_byte_span portion, "header"); } std::size_t post_header_size{0U}; - if (fde_post_header) { + if (context.has_fde_processed()) { // if format_description event has already been encountered in the stream, // we take post-header length from it - post_header_size = fde_post_header->get_post_header_length(type_code); + post_header_size = context.get_current_post_header_length(type_code); } else { // we expect that we can receive only 2 events before there is a // format_description event we can refer to: rotate (with artificial @@ -112,6 +112,7 @@ event::event(util::const_byte_span portion, footer_size); footer_.emplace(footer_portion); }; + context.process_event(*this); } void event::emplace_post_header(code_type code, util::const_byte_span portion) { @@ -126,7 +127,7 @@ void event::emplace_post_header(code_type code, util::const_byte_span portion) { // then, we define an alias for a container that can store // '' such member function pointers using emplace_function_container = - std::array; + std::array; // after that we declare a constexpr instance of such array and initialize it // with immediately invoked lambda static constexpr emplace_function_container emplace_functions{ @@ -168,7 +169,7 @@ void event::emplace_body(code_type code, util::const_byte_span portion) { // here we use the same technique as in 'emplace_post_header()' using emplace_function = void (event::*)(util::const_byte_span); using emplace_function_container = - std::array; + std::array; static constexpr emplace_function_container emplace_functions{ []( std::index_sequence) -> emplace_function_container { diff --git a/src/binsrv/event/event.hpp b/src/binsrv/event/event.hpp index a75332d..5736507 100644 --- a/src/binsrv/event/event.hpp +++ b/src/binsrv/event/event.hpp @@ -22,29 +22,22 @@ #include "binsrv/event/format_description_post_header_impl.hpp" // IWYU pragma: export #include "binsrv/event/generic_body.hpp" // IWYU pragma: export #include "binsrv/event/generic_post_header.hpp" // IWYU pragma: export +#include "binsrv/event/reader_context_fwd.hpp" #include "binsrv/event/rotate_body_impl.hpp" // IWYU pragma: export #include "binsrv/event/rotate_post_header_impl.hpp" // IWYU pragma: export #include "binsrv/event/unknown_body.hpp" // IWYU pragma: export #include "binsrv/event/unknown_post_header.hpp" // IWYU pragma: export #include "util/byte_span_fwd.hpp" -#include "util/conversion_helpers.hpp" namespace binsrv::event { -using optional_format_description_post_header = - std::optional>; -using optional_format_description_body = - std::optional>; - class [[nodiscard]] event { private: - static constexpr std::size_t number_of_events{ - util::enum_to_index(code_type::delimiter)}; - // here we create an index sequence (std::index_sequence) specialized // with the following std::size_t constant pack: 0 .. - using code_index_sequence = std::make_index_sequence; + using code_index_sequence = + std::make_index_sequence; // almost all boost::mp11 algorithms accept lists of types (rather than // lists of constants), so we convert std::index_sequence into // boost::mp11::mp_list of std::integral_constant types @@ -72,8 +65,8 @@ class [[nodiscard]] event { using post_header_variant = boost::mp11::mp_rename; - // identical techniqure is used to obtain the std::variant of all possible - // unique event bodyies + // identical technique is used to obtain the std::variant of all possible + // unique event bodies template using index_to_body_mf = generic_body(Index::value)>; @@ -86,17 +79,26 @@ class [[nodiscard]] event { using optional_footer = std::optional