Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added reader_context class #27

Merged
merged 1 commit into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 11 additions & 15 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand All @@ -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<binsrv::event::generic_post_header<
binsrv::event::code_type::format_description>>(
generic_event.get_post_header());
const auto &local_fde_body = std::get<binsrv::event::generic_body<
binsrv::event::code_type::format_description>>(
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<binsrv::event::code_type::format_description>();

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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/binsrv/event/common_header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@

#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"

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);

Expand Down
25 changes: 13 additions & 12 deletions src/binsrv/event/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
#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"
#include "util/exception_location_helpers.hpp"

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) <
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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
// '<number_of_events>' such member function pointers
using emplace_function_container =
std::array<emplace_function, number_of_events>;
std::array<emplace_function, default_number_of_events>;
// after that we declare a constexpr instance of such array and initialize it
// with immediately invoked lambda
static constexpr emplace_function_container emplace_functions{
Expand Down Expand Up @@ -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<emplace_function, number_of_events>;
std::array<emplace_function, default_number_of_events>;
static constexpr emplace_function_container emplace_functions{
[]<std::size_t... IndexPack>(
std::index_sequence<IndexPack...>) -> emplace_function_container {
Expand Down
36 changes: 19 additions & 17 deletions src/binsrv/event/event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<generic_post_header<code_type::format_description>>;
using optional_format_description_body =
std::optional<generic_body<code_type::format_description>>;

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 .. <number_of_events>
using code_index_sequence = std::make_index_sequence<number_of_events>;
using code_index_sequence =
std::make_index_sequence<default_number_of_events>;
// 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
Expand Down Expand Up @@ -72,8 +65,8 @@ class [[nodiscard]] event {
using post_header_variant =
boost::mp11::mp_rename<unique_post_header_type_list, std::variant>;

// 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 <typename Index>
using index_to_body_mf =
generic_body<util::index_to_enum<code_type>(Index::value)>;
Expand All @@ -86,17 +79,26 @@ class [[nodiscard]] event {
using optional_footer = std::optional<footer>;

public:
event(util::const_byte_span portion,
const optional_format_description_post_header &fde_post_header,
const optional_format_description_body &fde_body);
event(reader_context &context, util::const_byte_span portion);

[[nodiscard]] const common_header &get_common_header() const noexcept {
return common_header_;
}
[[nodiscard]] const post_header_variant &get_post_header() const noexcept {
[[nodiscard]] const post_header_variant &
get_generic_post_header() const noexcept {
return post_header_;
}
[[nodiscard]] const body_variant &get_body() const noexcept { return body_; }
template <code_type Code> [[nodiscard]] const auto &get_post_header() const {
return std::get<generic_post_header<Code>>(get_generic_post_header());
}

[[nodiscard]] const body_variant &get_generic_body() const noexcept {
return body_;
}
template <code_type Code> [[nodiscard]] const auto &get_body() const {
return std::get<generic_body<Code>>(get_generic_body());
}

[[nodiscard]] const optional_footer &get_footer() const noexcept {
return footer_;
}
Expand Down
21 changes: 0 additions & 21 deletions src/binsrv/event/format_description_post_header_impl.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "binsrv/event/format_description_post_header_impl.hpp"

#include <cstddef>
#include <iterator>
#include <stdexcept>
#include <string>
#include <string_view>
Expand All @@ -16,7 +14,6 @@

#include "util/byte_span.hpp"
#include "util/byte_span_extractors.hpp"
#include "util/conversion_helpers.hpp"
#include "util/exception_location_helpers.hpp"

namespace binsrv::event {
Expand Down Expand Up @@ -49,11 +46,6 @@ generic_post_header_impl<code_type::format_description>::
"mismatch in "
"generic_post_header_impl<code_type::format_description>::"
"server_version_length");
static_assert(number_of_events ==
util::enum_to_index(code_type::delimiter) - 1U,
"mismatch in "
"generic_post_header_impl<code_type::format_description>::"
"number_of_events");

// TODO: initialize size_in_bytes directly based on the sum of fields
// widths instead of this static_assert
Expand Down Expand Up @@ -103,17 +95,4 @@ generic_post_header_impl<code_type::format_description>::get_server_version()
boost::posix_time::from_time_t(get_create_timestamp()));
}

[[nodiscard]] std::size_t
generic_post_header_impl<code_type::format_description>::get_post_header_length(
code_type code) const noexcept {
// here the very first "unknown" code is not included in the array by the
// spec
const auto index{util::enum_to_index(code)};
if (index == 0U || index >= util::enum_to_index(code_type::delimiter)) {
return 0U;
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
return static_cast<std::size_t>(post_header_lengths_[index - 1U]);
}

} // namespace binsrv::event
15 changes: 7 additions & 8 deletions src/binsrv/event/format_description_post_header_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <string>
#include <string_view>

#include "binsrv/event/protocol_traits.hpp"

#include "util/byte_span_fwd.hpp"

namespace binsrv::event {
Expand All @@ -18,15 +20,10 @@ template <>
class [[nodiscard]] generic_post_header_impl<code_type::format_description> {
public:
static constexpr std::size_t server_version_length{50U};
static constexpr std::size_t number_of_events{41U};
static constexpr std::size_t size_in_bytes{98U};

private:
using server_version_storage = std::array<std::byte, server_version_length>;
using post_header_lengths_storage =
std::array<std::uint8_t, number_of_events>;

public:
explicit generic_post_header_impl(util::const_byte_span portion);

[[nodiscard]] std::uint16_t get_binlog_version_raw() const noexcept {
Expand Down Expand Up @@ -55,19 +52,21 @@ class [[nodiscard]] generic_post_header_impl<code_type::format_description> {
return static_cast<std::size_t>(get_common_header_length_raw());
}

[[nodiscard]] const post_header_lengths_storage &
[[nodiscard]] const post_header_length_container &
get_post_header_lengths_raw() const noexcept {
return post_header_lengths_;
}
[[nodiscard]] std::size_t
get_post_header_length(code_type code) const noexcept;
get_post_header_length(code_type code) const noexcept {
return get_post_header_length_for_code(post_header_lengths_, code);
}

private:
// the members are deliberately reordered for better packing
std::uint32_t create_timestamp_{}; // 2
server_version_storage server_version_{}; // 1
std::uint16_t binlog_version_{}; // 0
post_header_lengths_storage post_header_lengths_{}; // 4
post_header_length_container post_header_lengths_{}; // 4
std::uint8_t common_header_length_{}; // 3
};

Expand Down
28 changes: 28 additions & 0 deletions src/binsrv/event/protocol_traits.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "binsrv/event/protocol_traits.hpp"

#include <cstddef>

#include "binsrv/event/code_type.hpp"

#include "util/conversion_helpers.hpp"

namespace binsrv::event {

[[nodiscard]] std::size_t
get_post_header_length_for_code(const post_header_length_container &storage,
code_type code) noexcept {
static_assert(default_number_of_events ==
util::enum_to_index(code_type::delimiter),
"mismatch between number_of_events and code_type enum");

// here the very first "unknown" code is not included in the array by the
// spec
const auto index{util::enum_to_index(code)};
if (index == 0U || index >= default_number_of_events) {
return 0U;
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
return static_cast<std::size_t>(storage[index - 1U]);
}

} // namespace binsrv::event
24 changes: 24 additions & 0 deletions src/binsrv/event/protocol_traits.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef BINSRV_EVENT_PROTOCOL_TRAITS_HPP
#define BINSRV_EVENT_PROTOCOL_TRAITS_HPP

#include "binsrv/event/protocol_traits_fwd.hpp" // IWYU pragma: export

#include <array>
#include <cstddef>
#include <cstdint>

#include "binsrv/event/code_type_fwd.hpp"

namespace binsrv::event {

// we do not store length for the first element which is the "unknown" event
using post_header_length_container =
std::array<std::uint8_t, default_number_of_events - 1U>;

[[nodiscard]] std::size_t
get_post_header_length_for_code(const post_header_length_container &storage,
code_type code) noexcept;

} // namespace binsrv::event

#endif // BINSRV_EVENT_PROTOCOL_TRAITS_HPP
Loading