Fix xbcloud put "out-of-order chunk" failure on sparse chunks (page-compressed tables) - #1781
Open
egezonberisha wants to merge 1 commit into
Open
Conversation
put_func advanced the expected per-file offset by chunk.length only, ignoring the sparse map, and skipped offset/checksum validation for XB_CHUNK_TYPE_SPARSE chunks. Streaming any tablespace that uses InnoDB page compression (COMPRESSION="zlib") therefore aborts with "out-of-order chunk" at the first payload chunk that follows a sparse chunk of the same file, while the identical stream extracts fine with xbstream -x. Mirror mode_extract's handling: validate checksum and offset for sparse chunks and advance the expected offset by the sparse map skips. Also free chunk.sparse_map before the per-iteration reset - the raw buffer's ownership moves to the upload buffer, the sparse map's does not, so it was leaked for every sparse chunk processed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
xtrabackup --backup --stream=xbstream | xbcloud putfails deterministically withwhenever the instance contains a tablespace using InnoDB page compression (
CREATE TABLE ... COMPRESSION="zlib") whose.ibdproduces a mix of sparse and non-sparse xbstream chunks. The stream itself is valid — piping the identical stream intoxbstream -xextracts correctly — the failure is inxbcloud put's offset bookkeeping. Observed in production on 8.4.0-6; the affected code is identical on current8.0,8.4, andtrunk.Root cause
For page-compressed tablespaces,
write_ibd_buffer()builds a sparse map from page contents and the backup emitsXB_CHUNK_TYPE_SPARSEchunks (backup_copy.cc#L502-L545; the xbstream datasink always advertises sparse support, ds_xbstream.cc#L94-L96).On the write side, the per-file stream offset advances by payload length plus the sum of the sparse-map holes (xbstream_write.cc#L258-L260), so the next chunk's
offsetfield on the wire jumps over the holes.xbstream -x(mode_extract) reads this back correctly — it advances its expected offset bychunk.lengthplus everysparse_map[i].skip(xbstream.cc#L625-L638).xbcloud put(put_func) does not:entry->offset += chunk.lengthunconditionally, ignoring the sparse map (xbcloud.cc#L912);XB_CHUNK_TYPE_PAYLOADchunks (xbcloud.cc#L863-L877).So while a file streams as SPARSE chunks,
entry->offsetsilently falls behind the real offset by the accumulated hole size. The moment the file produces a plain PAYLOAD chunk — the first--read-buffer-size(default 10 MiB) window containing zero compressed pages, e.g. a run of incompressible data — the check fires andxbcloud putaborts. The gap between "real" and "expected" in the error message equals the total punched-hole bytes up to that point.Because the failure only occurs when a payload chunk follows sparse chunks of the same file, it is data-dependent: a table can back up fine for months and then fail every run once its data distribution shifts. This is why the error is easy to misdiagnose as network/S3 flakiness — see PXB-3572 and this forum thread (same signature, closed Not a Bug after being attributed to network issues;
--curl-retriable-errorscannot fix it, and retries leave partial uploads in the bucket).Fix
Mirror
mode_extract's sparse handling input_func():XB_CHUNK_TYPE_SPARSEchunks too (xb_stream_validate_checksum()already supports them —xb_stream_read_chunk()seedschecksum_partwith the sparse map's CRC, xbstream_read.cc#L270-L288);chunk.length;chunk.sparse_mapbefore the per-iterationmemsetreset —chunk.raw_data's ownership moves to the upload buffer, but the sparse map (a separate allocation) does not, so it was leaked for every sparse chunk processed (possibly what PXB-3189 observed).No stored-object format change:
xbcloud putuploads raw chunk bytes, so backups uploaded with this fix restore with existingxbcloud get | xbstream -x, and previously-uploaded backups are unaffected.The change mirrors existing, exercised logic from
xbstream.cc; I have not run it against a full build, so please lean on CI/review accordingly.How to reproduce
Any 8.0/8.4 server with the datadir on a punch-hole-capable filesystem (ext4/xfs, default
innodb_page_size=16k), plus any S3 endpoint (local MinIO is fine):Happy to contribute this reproducer as a regression test if you can point me at the preferred harness for xbcloud tests.
Workarounds for affected users (until fixed)
--compress=zstd(or lz4) to xtrabackup: the compression datasink does not implement sparse writes, so the stream contains no SPARSE chunks; sparseness is restored at extract time viarestore_sparseness(). Restore needsxbstream -x --decompress.ALTER TABLE ... COMPRESSION='none'+OPTIMIZE TABLE).🤖 Generated with Claude Code