You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PXB-3862 : Combine scattered changed-page reads in page-tracking backups
https://perconadev.atlassian.net/browse/PXB-3862
Problem
-------
A page-tracking incremental reads only the pages the server marked as
changed. Consecutive changed pages are already read together in one
request; the problem is scattered changes. If the changed pages are
1, 3, 5, 7, 9
xtrabackup issues five single-page reads. Every read request costs a
full I/O round trip, so with scattered changes the copy phase is bound
by the number of requests instead of the amount of data, and an
incremental can take several times longer than a full scan of the
same file.
Fix
---
Read the whole range 1-9 in one request. The unchanged pages 2, 4, 6,
8 are read as filler and discarded by the existing incremental write
filter, which drops every page whose FIL_PAGE_LSN is older than
incremental_lsn. The backup's content and size are byte-for-byte
unchanged; only the read pattern changes.
A gap is worth combining across exactly when its bytes cost less than
one read request. That cost, in bytes of sequential transfer, is
round_trip * bandwidth - and no fixed number fits both a local NVMe
and a network volume, so it is measured at backup start
(probe_storage, xb_io_probe.h): twelve scattered single-page reads
give the round trip, 16MB of sequential reads the bandwidth, on the
largest changed data file (at least 64MB). Then
read_request_cost = round_trip * bandwidth / 1.5,
clamped to [64KB, 1MB], 512KB if unmeasurable
max_gap = read_request_cost / physical_page_size
The /1.5 margin absorbs copy-pipeline overhead and measurement noise,
erring toward reading less; it was calibrated on two instrumented
machines whose break-evens bound it from both sides. The
per-tablespace conversion lets compressed tablespaces combine across
the same byte cost. Filler bytes are always the actual gap sizes
present in the data, never the limit, so a generous limit reads
nothing extra.
--page-tracking-max-gap exposes the behaviour: "auto" (default) as
described; a page count pins one value for all tables and skips the
probe; 0 keeps the previous strict-consecutive reads.
Log messages
------------
Once per backup, the measurement:
pagetracking: calibrated storage (./test/t1.ibd): request round
trip 124 us, sequential read 984 MB/s -> one read request costs
~83KB of sequential transfer; gaps cheaper than this are combined
Per table with at least 1000 changed pages, when its copy finishes,
accumulated from what was actually read:
pagetracking: test/t1.ibd: 3196 changed pages in 3196 ranges (avg
gap 2.0 pages); max-gap=4 (auto) combined them into 2 reads:
request reduction 1598.0x, read amplification 2.98x; issued 16
read batches
"ranges" is the requests max-gap=0 would issue; "request reduction"
is the benefit and "read amplification" its price (bytes read divided
by changed bytes - read volume only, backup size is unaffected);
"issued" exceeds the group count only when a group is larger than
--read-buffer-size and is read in buffer-sized pieces. When the
typical gap costs more than one read request, an extra line names
both numbers and the pinned value to try, so a boundary case is
diagnosable from the log alone:
pagetracking: test/t1.ibd: typical gap 8.9 pages (143KB) costs
more than one read request (83KB); reads stay individual - if
sequential read throughput is high, --page-tracking-max-gap=9 may
be faster
Testing: unit tests (xb_page_group-t) cover the read request cost
model across device classes and the storage probe's failure modes; a
framework testcase sweeps change densities and asserts only
hardware-independent invariants - ranges vs combined reads vs issued
requests, auto vs strict, the cost floor and ceiling, and restore
correctness - and was verified to fail against a build with the
combining silently disabled.
0 commit comments