Fix page-tracking incremental backups reading unmodified page ranges between changed-page blocks#1768
Open
giezi wants to merge 1 commit into
Open
Fix page-tracking incremental backups reading unmodified page ranges between changed-page blocks#1768giezi wants to merge 1 commit into
giezi wants to merge 1 commit into
Conversation
range_get_next_page() is documented to leave current_page_it pointing at
the last page of the current contiguous block of changed pages. This is
what happens when the end of the page set is reached, but in the case
where the next changed page is simply not adjacent, the iterator is left
pointing at that next (non-adjacent) changed page.
The caller (rf_page_tracking_get_next_batch) then computes
ctxt->filter_batch_end = (*space->current_page_it) + 1;
which extends the read batch from the start of the current block all the
way to the next changed page, silently reading every unmodified page in
the gap between the two blocks. Iterated over a whole tablespace, the
backup ends up reading from the first changed page to the last changed
page of every .ibd file, gaps included.
For large tablespaces with sparsely distributed changed pages this
degenerates into reading nearly the entire data file and defeats the
purpose of page tracking. Observed in production on a 1.5 TB tablespace:
the mysqlbackup component reported only 452 changed pages (~7 MB), yet
xtrabackup read ~1.4 TB from that file, keeping an hourly incremental
backup busy for 20+ minutes at >1 GB/s read.
Fix: step the iterator back to the last page of the current contiguous
block before breaking, matching the documented behavior and the
end-of-set branch. The read batches then cover exactly the contiguous
changed-page ranges.
Author
|
Validation notes (simulation of the batch logic, 3000 randomized page sets plus edge cases, including read-buffer chunking):
|
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
--page-trackingincremental backups read far more data than the number of changed pages reported by themysqlbackupcomponent. For large tablespaces with sparsely distributed changed pages, the backup effectively reads the file from the first changed page to the last changed page, including all unmodified pages in between.Production evidence (PXB 8.0.35-34, Percona Server 8.0.44-35, ~5.5 TB datadir)
mysqlbackupcomponent reported 6,399 changed pages total (~100 MB) for one hourly incremental window; the resulting.deltafiles were only a few hundred KB each.xtrabackupread ~1.4-3+ TB per hourly incremental run at >1 GB/s, with the log timeline showing each large tablespace being read essentially end-to-end. A 1.5 TB tablespace with only 452 changed pages took 20 minutes of continuous sequential reads.full_scan_tablesapplied: no inplace DDL (MLOG_INDEX_LOAD) and no encryption changes occurred in the backup windows (verified viaperformance_schemadigests and logs).Root cause
pagetracking::range_get_next_page()is documented as:When the scan hits the end of the page set, the iterator is correctly stepped back (
--page_set->current_page_it). But when the loop breaks because the next changed page is not adjacent, the iterator is left pointing at that next, non-adjacent changed page.The caller
rf_page_tracking_get_next_batch()then computes:ctxt->filter_batch_end = (*space->current_page_it) + 1; ... *read_batch_len = ctxt->filter_batch_end * ctxt->page_size - ctxt->offset;so the read batch spans from the start of the current block through the entire gap up to and including the first page of the next block. Iterated across a tablespace, every gap between changed-page blocks is read.
Example: changed pages
{10, 11, 12, 50}result in pages 10-50 being read (41 pages) instead of pages 10-12 and 50 (4 pages). With changed pages near the beginning and end of a multi-TB file, this reads nearly the whole file.Fix
Step the iterator back to the last page of the current contiguous block before breaking, matching both the documented behavior and the existing end-of-set branch. Read batches then cover exactly the contiguous changed-page ranges.
The
UNIV_DEBUGhelperverify_skipped_pages()still validates that skipped gap pages contain no modifications in the LSN window.Notes
8.0,8.4, andtrunkbranches; this PR targetstrunkand the fix applies cleanly to the release branches.Made with Cursor