Skip to content

PBS-42 feature: Implement basic support for COM_BINLOG_DUMP packet handling (part 1) - #191

Merged
percona-ysorokin merged 1 commit into
Percona-Lab:mainfrom
percona-ysorokin:com_binlog_dump_range_reads
Sep 28, 2026
Merged

percona-ysorokin merged 1 commit into
Percona-Lab:mainfrom
percona-ysorokin:com_binlog_dump_range_reads

Conversation

@percona-ysorokin

@percona-ysorokin percona-ysorokin commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

https://perconadev.atlassian.net/browse/PBS-42

  • Introduced new 'util::byte_range' class for representing byte ranges
    in files. It supports empty ranges, full ranges, open-ended ranges,
    and specific byte ranges.
  • 'binsrv::basic_storage_backend' interface extended to support ranged
    reads (via optional parameter of type 'util::byte_range').
  • Increased the size of max in-memory object supported by the
    'get_object()' operation in both 's3' and 'filesystem' implementations
    of the 'binsrv::basic_storage_backend'.
  • Reworked 'util::read_file_content()' utility function to support
    ranged filesystem reads.
  • Fixed some typos in code comments.

Comment thread src/binsrv/s3_storage_backend.cpp Outdated
if (offset != 0 || length.has_value()) {
std::string range{"bytes=" + std::to_string(offset) + "-"};
if (length.has_value()) {
range += std::to_string(offset + length.value() - 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if offset == 0 and length == 0?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Yes, we'd better make an early return in this case.

"received memory content");
}
} else {
if (content_length > max_memory_object_size) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't stream_handler called after receiving the object from s3? So it is already in the memory.

@percona-ysorokin percona-ysorokin Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a compromise we had to make here. Unfortunately, there is no way in S3 API to "read no more than N bytes from an S3 object" in a single request. So, we either need to send another request (HeadObject) before this call, or simply rely on the fact that we won't be abusing this function.
See the TODO item above.
I don't like this either to be honest.

Comment thread src/util/file_operations_helpers.cpp Outdated
std::uint64_t read_length{};
if (length.has_value()) {
read_length = length.value();
if (offset + read_length > file_size) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overflow possible. use read_length > file_size - offset

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point.

public:
static constexpr std::size_t max_memory_object_size{1048576U};
// 256 MB
static constexpr std::size_t max_memory_object_size{256UZ << 20UZ};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have the same in s3_storage_backend

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will move this to basic_storage_backend.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The S3 ranged-read path can materialize oversized responses before enforcing the memory limit.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Adds ranged object/file reads via a new util::byte_range abstraction to support upcoming binlog streaming functionality.

Changes:

  • Adds byte-range validation and formatting.
  • Extends filesystem and S3 storage APIs with ranged reads.
  • Updates memory limits, callers, and related comments.
File Summary
src/​util/​file_operations_helpers.hpp Declares ranged file reads.
src/​util/​file_operations_helpers.cpp Implements ranged filesystem reads.
src/​util/​byte_range.hpp Defines the byte-range API.
src/​util/​byte_range.cpp Implements validation and formatting.
src/​util/​byte_range_fwd.hpp Adds the forward declaration.
src/​binsrv/​storage_core.hpp Corrects comments.
src/​binsrv/​storage_core.cpp Corrects comments.
src/​binsrv/​s3_storage_backend.hpp Updates the S3 backend interface.
src/​binsrv/​s3_storage_backend.cpp Implements S3 ranged requests.
src/​binsrv/​main_config.cpp Updates file-read usage.
src/​binsrv/​keyring_record_collection.cpp Updates file-read usage.
src/​binsrv/​filesystem_storage_backend.hpp Updates the filesystem backend interface.
src/​binsrv/​filesystem_storage_backend.cpp Implements ranged filesystem access.
src/​binsrv/​basic_storage_backend.hpp Extends the backend API and memory limit.
src/​binsrv/​basic_storage_backend.cpp Forwards ranges to implementations.
mtr/​binlog_streaming/​t/​checkpointing.test Corrects a comment.
extra/​mysql_protocol/​mysql/​harness/​stdx/​ranges.h Corrects a comment.
CMakeLists.txt Registers byte-range sources.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +294 to +303
if (range.has_length()) {
if (content_length != range.get_length()) {
util::exception_location().raise<std::out_of_range>(
"The requested S3 object range does not match the length of the "
"received memory content");
}
} else {
if (content_length > max_memory_object_size) {
util::exception_location().raise<std::out_of_range>(
"S3 object is too large to be loaded in memory");
Comment thread src/util/byte_range.hpp

[[nodiscard]] bool has_length() const noexcept { return length_.has_value(); }

[[nodiscard]] std::uint64_t get_length() const noexcept {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will return 0 in both cases: if has length and it is 0 or it doesn't have length. That forces the caller to always check has_length() anyways. Wouldn't it be better to return optional?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I just wanted it to be a simple accessor (with noexcept).
And instead of

byte_range br{...};
if (bt.get_length_opt().vas_value()) {
  std::cout << bt.get_length_opt().value();
}

write something like

byte_range br{...};
if (bt.has_length()) {
  std::cout << bt.get_length();
}

Although I understand that value_or() makes another unnecessary nullness check in my implementation.

Comment thread src/util/byte_range.cpp
if (length_.has_value()) {
result += std::to_string(offset_ + *length_ - 1ULL);
}
return result;

@kamil-holubicki kamil-holubicki Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be strange to get empty string, when is_full and on the other hand have an exception when is_empty
OK, I understand that it is used to form HTTP request, but in such a case it is rather an s3 class thing, not byte_range class responsibility. In other words, when I call to_string() I expect it to return meaningful string for logs for example, not a specific behavior that only s3 backend knows why

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. If we extracted this byte_range into util as a generic reusable component, let's not bind us to S3 format.

…ndling (part 1)

https://perconadev.atlassian.net/browse/PBS-42

* Introduced new 'util::byte_range' class for representing byte ranges
  in files. It supports empty ranges, full ranges, open-ended ranges,
  and specific byte ranges.
* 'binsrv::basic_storage_backend' interface extended to support ranged
  reads (via optional parameter of type 'util::byte_range').
* Increased the size of max in-memory object supported by the
  'get_object()' operation in both 's3' and 'filesystem' implementations
  of the 'binsrv::basic_storage_backend'.
* Reworked 'util::read_file_content()' utility function to support
  ranged filesystem reads.
* Fixed some typos in code comments.
@percona-ysorokin
percona-ysorokin force-pushed the com_binlog_dump_range_reads branch from 883fb21 to e06bdf2 Compare September 24, 2026 12:57
@percona-ysorokin
percona-ysorokin merged commit 716d245 into Percona-Lab:main Sep 28, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants