From 48d9dbc43534acfcc141af8d03dcd2bc7a1bcd0e Mon Sep 17 00:00:00 2001 From: Yura Sorokin Date: Fri, 13 Feb 2026 17:43:23 +0100 Subject: [PATCH] PS-10281 feature: Implement logic for search_by_gtid_set mode (part 2) https://perconadev.atlassian.net/browse/PS-10281 Binlog metadata JSON files now include "gtids" associated with individual files in readable format, e.g. "11111111-aaaa-1111-aaaa-111111111111:1-3:5, 22222222-bbbb-2222-bbbb-222222222222:11-13:15". Individual binlog file records returned in the 'search_by_timestamp' mode now also include associated "gtids". Fixed discrepancy in 'binsrv::storage::is_empty()' method - it used to return exactly the opposite value. --- src/app.cpp | 16 +++---- src/binsrv/binlog_file_metadata.cpp | 42 +------------------ src/binsrv/binlog_file_metadata.hpp | 5 +-- src/binsrv/models/binlog_file_record.hpp | 3 ++ .../models/search_by_timestamp_response.cpp | 12 +++--- .../models/search_by_timestamp_response.hpp | 6 ++- src/binsrv/storage.cpp | 4 +- src/binsrv/storage.hpp | 6 +-- 8 files changed, 29 insertions(+), 65 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index d660388..7621e20 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -257,12 +257,12 @@ void log_storage_info(binsrv::basic_logger &logger, msg.clear(); if (storage.is_empty()) { + msg = "binlog storage initialized on an empty directory"; + } else { msg = "binlog storage initialized at \""; msg += storage.get_current_binlog_name(); msg += "\":"; msg += std::to_string(storage.get_current_position()); - } else { - msg = "binlog storage initialized on an empty directory"; } logger.log(binsrv::log_severity::info, msg); } @@ -317,11 +317,11 @@ void log_replication_info( msg += ", starting from "; if (replication_mode == binsrv::replication_mode_type::position) { if (storage.is_empty()) { + msg += "the very beginning"; + } else { msg += storage.get_current_binlog_name(); msg += ":"; msg += std::to_string(storage.get_current_position()); - } else { - msg += "the very beginning"; } } else { const auto >ids{storage.get_gtids()}; @@ -547,12 +547,12 @@ bool open_connection_and_switch_to_replication( verify_checksum, blocking_mode); } else { if (storage.is_empty()) { + connection.switch_to_position_replication(server_id, verify_checksum, + blocking_mode); + } else { connection.switch_to_position_replication( server_id, storage.get_current_binlog_name(), storage.get_current_position(), verify_checksum, blocking_mode); - } else { - connection.switch_to_position_replication(server_id, verify_checksum, - blocking_mode); } } } catch (const easymysql::core_error &) { @@ -720,7 +720,7 @@ bool handle_search_by_timestamp(std::string_view config_file_path, break; } response.add_record(record.name, record.size, - storage.get_binlog_uri(record.name), + storage.get_binlog_uri(record.name), record.gtids, record.timestamps.get_min_timestamp().get_value(), record.timestamps.get_max_timestamp().get_value()); } diff --git a/src/binsrv/binlog_file_metadata.cpp b/src/binsrv/binlog_file_metadata.cpp index 2e575cf..4b761b3 100644 --- a/src/binsrv/binlog_file_metadata.cpp +++ b/src/binsrv/binlog_file_metadata.cpp @@ -18,21 +18,12 @@ #include #include #include -#include - -#include #include #include #include -// needed for binsrv::gtids::gtid_set_storage -#include // IWYU pragma: keep - -#include "binsrv/gtids/common_types.hpp" -#include "binsrv/gtids/gtid_set.hpp" - -#include "util/byte_span.hpp" +#include "util/exception_location_helpers.hpp" #include "util/nv_tuple_from_json.hpp" #include "util/nv_tuple_to_json.hpp" @@ -55,37 +46,6 @@ binlog_file_metadata::binlog_file_metadata(std::string_view data) : impl_{} { return boost::json::serialize(json_value); } -[[nodiscard]] gtids::optional_gtid_set binlog_file_metadata::get_gtids() const { - const auto &optional_gtids{root().get<"gtids">()}; - if (!optional_gtids.has_value()) { - return {}; - } - - const auto &encoded_gtids{optional_gtids.value()}; - std::string decoded_gtids(std::size(encoded_gtids) / 2U, 'x'); - boost::algorithm::unhex(encoded_gtids, std::data(decoded_gtids)); - return gtids::optional_gtid_set{std::in_place, - util::as_const_byte_span(decoded_gtids)}; -} - -void binlog_file_metadata::set_gtids(const gtids::optional_gtid_set >ids) { - auto &optional_gtids{root().get<"gtids">()}; - if (!gtids.has_value()) { - optional_gtids.reset(); - return; - } - const auto encoded_size{gtids.value().calculate_encoded_size()}; - - gtids::gtid_set_storage buffer(encoded_size); - util::byte_span destination{buffer}; - gtids.value().encode_to(destination); - - std::string encoded_gtids(std::size(buffer) * 2U, 'x'); - const auto buffer_sv{util::as_string_view(std::as_const(buffer))}; - boost::algorithm::hex_lower(buffer_sv, std::data(encoded_gtids)); - optional_gtids.emplace(std::move(encoded_gtids)); -} - void binlog_file_metadata::validate() const { if (root().get<"version">() != expected_binlog_file_metadata_version) { util::exception_location().raise( diff --git a/src/binsrv/binlog_file_metadata.hpp b/src/binsrv/binlog_file_metadata.hpp index f2007fe..906d4f2 100644 --- a/src/binsrv/binlog_file_metadata.hpp +++ b/src/binsrv/binlog_file_metadata.hpp @@ -26,7 +26,6 @@ #include "binsrv/gtids/gtid_set.hpp" -#include "util/common_optional_types.hpp" #include "util/nv_tuple.hpp" namespace binsrv { @@ -37,7 +36,7 @@ class [[nodiscard]] binlog_file_metadata { // clang-format off util::nv<"version", std::uint32_t>, util::nv<"size", std::uint64_t>, - util::nv<"gtids", util::optional_string>, + util::nv<"gtids", gtids::optional_gtid_set>, util::nv<"min_timestamp", ctime_timestamp>, util::nv<"max_timestamp", ctime_timestamp> // clang-format on @@ -56,8 +55,6 @@ class [[nodiscard]] binlog_file_metadata { [[nodiscard]] bool has_gtids() const noexcept { return impl_.get<"gtids">().has_value(); } - [[nodiscard]] gtids::optional_gtid_set get_gtids() const; - void set_gtids(const gtids::optional_gtid_set >ids); private: impl_type impl_; diff --git a/src/binsrv/models/binlog_file_record.hpp b/src/binsrv/models/binlog_file_record.hpp index ec17ea7..13b29cc 100644 --- a/src/binsrv/models/binlog_file_record.hpp +++ b/src/binsrv/models/binlog_file_record.hpp @@ -23,6 +23,8 @@ #include "binsrv/ctime_timestamp.hpp" +#include "binsrv/gtids/gtid_set.hpp" + #include "util/nv_tuple.hpp" namespace binsrv::models { @@ -33,6 +35,7 @@ struct [[nodiscard]] binlog_file_record util::nv<"name", std::string>, util::nv<"size", std::uint64_t>, util::nv<"uri", std::string>, + util::nv<"gtids", gtids::optional_gtid_set>, util::nv<"min_timestamp", ctime_timestamp>, util::nv<"max_timestamp", ctime_timestamp> // clang-format on diff --git a/src/binsrv/models/search_by_timestamp_response.cpp b/src/binsrv/models/search_by_timestamp_response.cpp index 63eae75..f35b865 100644 --- a/src/binsrv/models/search_by_timestamp_response.cpp +++ b/src/binsrv/models/search_by_timestamp_response.cpp @@ -24,6 +24,8 @@ #include #include +#include "binsrv/gtids/gtid_set.hpp" + #include "binsrv/models/binlog_file_record.hpp" #include "binsrv/models/response_status_type.hpp" @@ -53,14 +55,14 @@ search_by_timestamp_response::~search_by_timestamp_response() = default; return boost::json::serialize(json_value); } -void search_by_timestamp_response::add_record(std::string_view name, - std::uint64_t size, - std::string_view uri, - std::time_t min_timestamp, - std::time_t max_timestamp) { +void search_by_timestamp_response::add_record( + std::string_view name, std::uint64_t size, std::string_view uri, + const gtids::optional_gtid_set >ids, std::time_t min_timestamp, + std::time_t max_timestamp) { binlog_file_record record{{{std::string{name}}, {size}, {std::string{uri}}, + {gtids}, {ctime_timestamp{min_timestamp}}, {ctime_timestamp{max_timestamp}}}}; impl_.template get<"result">().emplace_back(std::move(record)); diff --git a/src/binsrv/models/search_by_timestamp_response.hpp b/src/binsrv/models/search_by_timestamp_response.hpp index 08c3c89..e5caf89 100644 --- a/src/binsrv/models/search_by_timestamp_response.hpp +++ b/src/binsrv/models/search_by_timestamp_response.hpp @@ -24,6 +24,8 @@ #include #include +#include "binsrv/gtids/gtid_set_fwd.hpp" + #include "binsrv/models/binlog_file_record_fwd.hpp" #include "binsrv/models/response_status_type_fwd.hpp" @@ -57,8 +59,8 @@ class [[nodiscard]] search_by_timestamp_response { [[nodiscard]] auto &root() noexcept { return impl_; } void add_record(std::string_view name, std::uint64_t size, - std::string_view uri, std::time_t min_timestamp, - std::time_t max_timestamp); + std::string_view uri, const gtids::optional_gtid_set >ids, + std::time_t min_timestamp, std::time_t max_timestamp); private: impl_type impl_; diff --git a/src/binsrv/storage.cpp b/src/binsrv/storage.cpp index 326c3b9..02dc4d8 100644 --- a/src/binsrv/storage.cpp +++ b/src/binsrv/storage.cpp @@ -464,7 +464,7 @@ storage::load_binlog_metadata(std::string_view binlog_name) const { return binlog_record{.name = std::string(binlog_name), .size = metadata.root().get<"size">(), - .gtids = metadata.get_gtids(), + .gtids = metadata.root().get<"gtids">(), .timestamps = {metadata.root().get<"min_timestamp">(), metadata.root().get<"max_timestamp">()}}; } @@ -488,7 +488,7 @@ void storage::validate_binlog_metadata(const binlog_record &record) const { void storage::save_binlog_metadata(const binlog_record &record) const { binlog_file_metadata metadata{}; metadata.root().get<"size">() = record.size; - metadata.set_gtids(record.gtids); + metadata.root().get<"gtids">() = record.gtids; metadata.root().get<"min_timestamp">() = ctime_timestamp{record.timestamps.get_min_timestamp()}; metadata.root().get<"max_timestamp">() = diff --git a/src/binsrv/storage.hpp b/src/binsrv/storage.hpp index a0af80a..aed8750 100644 --- a/src/binsrv/storage.hpp +++ b/src/binsrv/storage.hpp @@ -79,10 +79,10 @@ class [[nodiscard]] storage { return binlog_records_; } [[nodiscard]] bool is_empty() const noexcept { - return !binlog_records_.empty(); + return binlog_records_.empty(); } [[nodiscard]] std::string_view get_current_binlog_name() const noexcept { - return is_empty() ? get_current_binlog_record().name : std::string_view{}; + return is_empty() ? std::string_view{} : get_current_binlog_record().name; } [[nodiscard]] std::uint64_t get_current_position() const noexcept { return get_flushed_position() + std::size(event_buffer_); @@ -162,7 +162,7 @@ class [[nodiscard]] storage { return last_transaction_boundary_position_in_event_buffer_ != 0ULL; } [[nodiscard]] std::uint64_t get_flushed_position() const noexcept { - return is_empty() ? get_current_binlog_record().size : 0ULL; + return is_empty() ? 0ULL : get_current_binlog_record().size; } [[nodiscard]] std::uint64_t get_ready_to_flush_position() const noexcept { return get_flushed_position() +