create: --map and --reuse-from for efficient block device snapshot backups - #10137
Open
ThomasWaldmann wants to merge 3 commits into
Open
create: --map and --reuse-from for efficient block device snapshot backups#10137ThomasWaldmann wants to merge 3 commits into
ThomasWaldmann wants to merge 3 commits into
Conversation
An input map describes the content ranges of the single input file: data ranges are read and stored, zero ranges are stored as holes without reading them. Primary use case: backing up snapshots of large (esp. thin-provisioned) block devices, where the storage layer knows which ranges are in use. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…orgbackup#4363 For input map ranges marked "same", reuse the chunks of the reference archive's item instead of reading the input. Reference chunks that only partially overlap "same" ranges are re-read completely, so the result is correct with any chunker; with the fixed chunker, read windows align with the reference chunk grid. Reference chunks missing from the repo are read again (like the files cache does on a lost chunk). Together with --map, this implements efficient incremental backups of block device snapshots: only changed ranges need to be read, e.g. as reported by thin_delta for LVM thin volume snapshots. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…a, see borgbackup#4363 Converts thin_dump XML (full mode: allocation map of one thin LV) and thin_delta XML (delta mode: differences between two thin snapshots) into the borg create --map format. The docstring documents the full workflow including the reserve/release_metadata_snap steps and the snapshot discipline needed for --reuse-from. Also add a docs section pointing from the --read-special LVM example to the input map based approach. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #10137 +/- ##
==========================================
- Coverage 87.05% 86.19% -0.86%
==========================================
Files 101 101
Lines 17848 17999 +151
Branches 2705 2752 +47
==========================================
- Hits 15538 15515 -23
- Misses 1609 1781 +172
- Partials 701 703 +2 ☔ View full report in Codecov by Harness. |
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.
Implements the idea from #4363: efficiently back up snapshots of (thin provisioned) block devices by not reading the parts whose contents we already know.
borg create --map MAPFILEGives borg an externally generated map of the input's content ranges, so it does not need to read all of the input. The map file has one range per line,
START LENGTH STATE(decimal or 0x hex),#starts a comment:data: read and back up that range.zero: the range reads as all-zero bytes - borg stores a hole of that size without reading it.The map must be sorted, contiguous, start at offset 0 and cover the exact input size (a mismatch is an error - that catches maps belonging to a different input).
--maprequires exactly one input path, a regular file or (with--read-special) a block device.This alone already enables cheap full backups of thin LVs: only the allocated ranges are read.
The chunkers already accepted an
fmap(andFileFMAPReaderalready handled partial maps) - this just exposes it.borg create --reuse-from ARCHIVE [--reuse-path PATH]Adds a third map state,
same: the range is identical to that range of the input as backed up in the reference archive (usually the backup of the previous snapshot). For such ranges, borg reuses the reference item's chunks instead of reading the input.build_reuse_plan()walks the reference item's chunk list with cumulative offsets: a reference chunk is reused if its whole extent lies insidesameranges and the chunk still exists in the repo (otherwise it is read again, like the files cache does when it lost a chunk). Reference chunks that only partially overlapsameranges are re-read completely, so the byte stream is preserved and the result is correct with any chunker; with a fixed block size chunker, read windows align with the reference chunk grid and nothing is re-read at the edges. Each read segment gets its ownchunkify()call, so chunks never span a gap left by reused parts. Growing and shrinking inputs are handled (tail beyond the reference chunks is read, reference chunks beyond the new size are dropped).The result is an ordinary, complete item - no repo/archive format changes,
extract/check/mount/diffwork as usual.scripts/lvm-thin-map.pyConverts thin-provisioning-tools XML into the map format:
fullmode:thin_dump --dev-idoutput -> allocated ranges asdata, everything elsezero.deltamode:thin_deltaoutput ->same/different/right_only/left_onlymapped tosame/data/data/zero.The script's docstring documents the complete workflow (snapshot creation,
reserve_metadata_snap/release_metadata_snap, which snapshot to keep as the reference for the next delta).docs/usage/notes.rstpoints from the existing--read-specialLVM example to this approach.Typical usage:
Trust
The map is trusted: if it is wrong, the archive does not match the input and borg cannot detect that. This is documented in the
--helpepilog and the docs, together with the advice to do periodic full read backups. Note that thin pool metadata is the same information the kernel uses to serve reads, so it is authoritative rather than heuristic - unlike e.g. mtime based change detection.Tests
build_reuse_plan(reuse/read/partial overlap/merging, zero ranges, grown/shrunk input, missing chunk).--mapand--reuse-from, incl. a test that deliberately puts different data in a range declaredsameto prove the reference chunks are really reused (and one forzero), a CDC test with an unaligned change, resize tests and the error cases.