check: detect missing packs referenced by the index (#9898) - #10069
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #10069 +/- ##
==========================================
- Coverage 86.77% 84.65% -2.13%
==========================================
Files 98 99 +1
Lines 17277 17389 +112
Branches 2622 2642 +20
==========================================
- Hits 14992 14720 -272
- Misses 1587 1982 +395
+ Partials 698 687 -11 ☔ View full report in Codecov by Harness. |
|
ping @mr-raj12 |
With an intact index, load the chunk index and report any referenced pack id that is absent from packs/. Such packs are counted as errors so the check fails. Skipped for a corrupt or invalid index, which is rebuilt from the packs on next use.
Report packs present in packs/ that no index entry references at info level; they are interrupted-operation leftovers, not errors. Reword the missing-pack error to match the summary and correct the invalid-index comment.
3ff6623 to
dfcc12b
Compare
|
Review by Claude: Thanks for working on this! I reviewed the branch locally (built it, ran the tests, probed the behaviour). The direction is right and this is what #9898 asks for, but as it stands there is one crash regression, one silent no-op path, and a cost regression that undoes what Blockers1. The cross-check calls On master the same repo checks clean. Note that the PR works around this in the test file rather than fixing it: 2. The check silently becomes a no-op exactly when it matters. If the index fragments cannot be loaded, The fallback also does a full pack-header scan of the whole repo, which the docstring a few paragraphs above explicitly rules out ("reading every pack to do so would be far too slow and expensive for a routine (e.g. cron) check"). This needs a no-fallback path (a 3. The whole chunk index is now downloaded and built on every repository check - twice.
On top of that it builds a throwaway index instead of using the Using Should be fixed before merge
Non-blocking
One thing that is not a problem, contrary to my first reading: concurrency. |
|
Item 1 is an attack scenario - unlikely to happen just by corruption. Rebase on current master seems indicated. |
|
ping? |
…orgbackup#9898) Read the chunk index from its fragments only for the missing-pack cross-check; skip it (still passing) when the index cannot be read that way, and on partial (--max-duration) runs. Guard ChunkIndex.read against hash-valid-but-unreadable fragments.
|
Re-reviewed at Fixed since my last passThe crash on an unparseable Still open1. The double index build is still there - this is the "at least one rebuild too much" from my earlier comment. Verified by instrumenting
One line fixes it: replace 2. A partial check now says "no problems found" on a repo that lost data. Same repo, back to back: That skip came out of my last review and I framed it badly: my cost objection was really about the double build (item 1). The cross-check itself is a single index load - O(index), not proportional to pack bytes - so skipping it buys very little, and it buys that with a false all-clear in exactly the mode people run from cron on big / cloud repos, which is the use case I described in #9898. Better: run it on partial runs too, before the pack loop so that 3. Retry amplification on an unreadable fragment. 4. This duplicates logic
So compact sends the user to a repair that check says does not exist yet. The wording should be aligned, and ideally the two should share one helper - they also differ in granularity (compact counts index entries, check counts packs). (Unrelated pre-existing nit I noticed there: "1 index entries".) Smaller things
Items 1 and 2 should be fixed before this can go in, 3 and 4 are worth doing now while the code is fresh, the rest is polish. |
…ing packs, reuse it as .chunks (borgbackup#9898)
…corrupt fragment rebuilds instead of retrying, add fragments_only write guard compact/repo-compress/check: align stale-pack wording to refs borgbackup#8572, fix singular grammar; list orphan pack ids at debug (borgbackup#9898)
Fixes #9898.
A read-only check verified pack and index integrity separately but never compared them, so a pack that the chunk index still referenced while missing from packs/ passed clean. The loss only showed up later, on extract.
With an intact index, check now reads the chunk index from its stored fragments and cross-checks its pack ids against packs/:
The cross-check reads the index from its fragments only, never rebuilding it from the packs (too slow for a routine check) and never writing to the repo. It is skipped, and the check still passes, when the index cannot be read that way: a corrupt or invalid index is rebuilt from the packs on next use (and so can never reference a missing pack), and a pack that is truly gone then surfaces as missing chunks in the archives check. It is also skipped on a partial run (--max-duration), which the full check's cross-check covers.
Tests cover the missing-pack detection, the clean case, the invalid-index skip, the unreadable-fragments skip, the partial-run skip, and the orphan-pack report.