Repository navigation
PBS-59 Reconcile storage against binlog index on startup - #195
Open
lukin-oleksiy wants to merge 2 commits into
Open
lukin-oleksiy wants to merge 2 commits into
lukin-oleksiy wants to merge 2 commits into
Conversation
lukin-oleksiy
force-pushed
the
PBS-59-auto-recovery-signal11
branch
2 times, most recently
from
September 30, 2026 11:07
5cec848 to
37a90ad
Compare
lukin-oleksiy
requested review from
percona-ysorokin
and
a balanced review from Copilot
October 1, 2026 09:10
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Ordinal validation can silently accept a missing leading binlog instead of reporting storage corruption.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Makes binlog metadata the storage source of truth and adds crash-time reconciliation.
Changes:
- Adds ordinals, purge horizons, and derived index regeneration.
- Adds durable filesystem writes and reconciliation tests/helpers.
- Updates Boost and AWS SDK discovery.
| File | Description |
|---|---|
src/binsrv/storage_metadata.hpp |
Adds purge horizon metadata. |
src/binsrv/storage_metadata.cpp |
Initializes the new field. |
src/binsrv/storage_metadata_fwd.hpp |
Bumps metadata version. |
src/binsrv/storage_core.hpp |
Defines reconciliation interfaces and state. |
src/binsrv/storage_core.cpp |
Implements recovery, purge, and index derivation. |
src/binsrv/filesystem_storage_backend.hpp |
Tracks the active stream path. |
src/binsrv/filesystem_storage_backend.cpp |
Fsyncs streamed data. |
src/binsrv/binlog_file_metadata.hpp |
Adds binlog ordinals. |
src/binsrv/binlog_file_metadata.cpp |
Initializes ordinal metadata. |
src/binsrv/binlog_file_metadata_fwd.hpp |
Bumps binlog metadata version. |
mtr/binlog_streaming/t/storage_reconciliation.test |
Tests reconciliation scenarios. |
mtr/binlog_streaming/r/storage_reconciliation.result |
Adds expected test output. |
mtr/binlog_streaming/include/upload_storage_object.inc |
Adds backend-neutral uploads. |
mtr/binlog_streaming/include/remove_storage_object.inc |
Adds backend-neutral removal. |
mtr/binlog_streaming/include/download_storage_object.inc |
Adds backend-neutral downloads. |
mtr/binlog_streaming/include/assert_storage_object_absent.inc |
Adds absence assertions. |
CMakeLists.txt |
Adjusts dependency discovery. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1005
to
+1011
| // 'records' is expected to be sorted by ordinal here, so any pair of | ||
| // adjacent records with non-consecutive ordinals indicates either a | ||
| // duplicate or a missing binlog metadata object | ||
| const auto gap_it{std::ranges::adjacent_find( | ||
| records, [](const binlog_record &previous, const binlog_record &next) { | ||
| return next.ordinal != previous.ordinal + 1ULL; | ||
| })}; |
lukin-oleksiy
force-pushed
the
PBS-59-auto-recovery-signal11
branch
from
October 8, 2026 10:30
37a90ad to
fcd02de
Compare
- Use BoostConfig.cmake (CMP0167 NEW) instead of the deprecated FindBoost
module and make the header-only 'asio' component optional, defining a
Boost::asio fallback target on top of Boost::headers when the Boost
installation (e.g. Debian / Ubuntu packages) does not provide one.
- When AWS SDK CPP is not found in the standard locations (the CMake
presets point CMAKE_PREFIX_PATH to the matching installation), also look
for an installation made by the AWS SDK CPP presets next to the source
tree ('../aws-sdk-cpp-install-<preset>'), so that a plain 'cmake' works
without installing the SDK into a system prefix. Several such
installations are reported as an error instead of picking an arbitrary
one.
- Source list: 'cout_logger' is replaced with 'ostream_logger', unused
'null_logger' is removed (the sources are changed in the next commit).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A hard kill between writing a new binlog file's metadata and updating
'binlog.index' left the storage unable to start ("storage contains an
object that is not referenced in the binlog index"). Interrupted purges
had the same problem.
Storage objects are now reconciled top-down when the storage is opened:
- 'binlog.index' is the source of truth for the set of binlog files.
Binlog data / metadata files not referenced in it (left after an
interrupted binlog file creation or an interrupted purge) and temporary
objects are garbage. A missing binlog index means that the storage has
no binlog files, unless the storage contains more than a single binlog
file, which is an error.
- Only objects whose names have the form of objects created by the
Binlog Server are considered; any other object is logged and left
intact.
- Binlog metadata is the source of truth for the binlog data file size:
the most recent binlog data file is truncated to the size recorded in
its metadata (also for encrypted files, as CTR keeps byte offsets).
- The storage is not opened if it cannot be made consistent: missing
binlog data file or invalid metadata of an indexed binlog, binlog data
file smaller than recorded, size mismatch in a non-latest binlog.
Garbage is removed only after the whole storage has been validated, so
nothing is removed from a storage that cannot be repaired.
- 'fetch' / 'pull' log every fix. 'purge_binlogs' appends its messages
to the configured log file marked with the '[storage-maintenance]' tag
(or prints them to stderr if no log file is configured). Log files are
now always written in the append mode (after truncation, unless the
content must be kept), so that messages from both processes do not
overwrite each other.
- 'list' / 'search_by_timestamp' / 'search_by_gtid_set' never modify the
storage; they print found problems and how they will be fixed to
stderr, using the configured logging level, and skip binlog files that
cannot be used. JSON responses are not changed.
- 'cout_logger' is generalized into 'ostream_logger' (stdout / stderr),
'logger_factory::create()' gets creation options, unused 'null_logger'
is removed.
- The filesystem backend now fsyncs stream data before returning, so
binlog metadata never describes bytes that are not on disk.
- Added 'storage_reconciliation' MTR test (plain and encrypted
combinations) and backend-agnostic storage object helper includes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lukin-oleksiy
force-pushed
the
PBS-59-auto-recovery-signal11
branch
from
October 8, 2026 11:04
fcd02de to
9f5e33e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Problem
A hard kill between writing a new binlog file's metadata and updating
binlog.indexleft the storage unable to start ("storage contains an objectthat is not referenced in the binlog index"). Interrupted purges had the same
problem.
Solution
When the storage is opened, it is reconciled top-down:
binlog.indexis the source of truth for the set of binlog files.Binlog data / metadata files not listed in it (left after an interrupted
binlog file creation or an interrupted purge) and
*.tmpobjects leftafter interrupted writes are garbage and are removed. A missing binlog
index means the storage has no binlog files, unless it contains more than
a single binlog file, which is an error (to avoid wiping the storage when
the index is lost).
<binlog>.json) is the source of truth for the datafile size. The most recent binlog data file is truncated to the recorded
size. This also works for encrypted files: AES-CTR keeps byte offsets, and
encryption resumes from an arbitrary (not block-aligned) offset.
Safety rules:
Server (
metadata.json,binlog.index,<base>.<seq>,<base>.<seq>.jsonand their
.tmpversions) are considered. Any other object (e.g. nested S3keys, operator's files) is logged and left intact.
file or invalid metadata of an indexed binlog, data file smaller than
recorded, size mismatch in a non-latest binlog, lost index.
nothing is removed from a storage that cannot be repaired.
purge_binlogswhile another instance is fetching / pulling to thesame storage remains unsupported (as already documented in README); the
repairs described above are not safe in that situation either.
Reporting
fetch/pull: every fix is logged with thewarningseverity.purge_binlogs: appends its messages to the configured log file (which maybe used by a running
fetch/pull) with the[storage-maintenance]tag;prints to stderr if no log file is configured.
fetch/pull), so messages from both processes do not overwrite eachother.
list/search_by_timestamp/search_by_gtid_set: never modify thestorage; problems and how they will be fixed are printed to stderr at the
configured logging level, binlog files that cannot be used are skipped.
Nothing is printed for a consistent storage.
Other changes
cout_loggeris generalized intoostream_logger(stdout / stderr),logger_factory::create()gets creation options, unusednull_loggerisremoved.
metadata never describes bytes that are not on disk.
CMakeLists.txtchanges): Boost lookup viaBoostConfig.cmake with a
Boost::asiofallback for distro packages; AWS SDKCPP fallback lookup in a single
../aws-sdk-cpp-install-<preset>directorynext to the source tree (several such directories are an error); updated
source list.
Testing
storage_reconciliationMTR test withplainandencryptedcombinations: garbage removal, foreign objects kept, querying-only
reporting, truncation (and resumed encryption at an unaligned offset,
verified by decrypting and comparing with the server's binlogs),
unrepairable storages with nothing removed,
purge_binlogslogging.binlog_streamingsuite (41 tests,--big-test) passes on the filebackend; the S3 backend was not tested.
🤖 Generated with Claude Code