Skip to content

fix(sizes): remove Logical mode — apparent size becomes a classified annotation (sparse/compressed)#31

Merged
rducom merged 1 commit into
mainfrom
fix/apparent-size-annotation
Jul 13, 2026
Merged

fix(sizes): remove Logical mode — apparent size becomes a classified annotation (sparse/compressed)#31
rducom merged 1 commit into
mainfrom
fix/apparent-size-annotation

Conversation

@rducom

@rducom rducom commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Problem

The global On disk / Logical toggle re-weighted the entire app by st_size. On sparse files the result read as a bug while being technically correct: three com.apple.container snapshots showed 512 GiB each (~1.3 GiB actually allocated), and the volume "total" reached 2.42 TiB on a 512 GiB disk. The data was right; the scope was wrong — no user question is answered by the apparent size of the whole disk, but "why does this file look huge / what happens if I copy it" needs answering in place.

Approach

One truth, annotated where it lies:

  • On-disk (allocated) size everywhere — treemap weights, outline, totals, file types. SizeMetric and all its dual-dimension cache plumbing (sortCacheMetric, FileListing.metric, layout invalidation by metric, world resets on metric flips) are removed.
  • Scanner classifies the gap at zero costATTR_CMN_FLAGS rides the existing getattrlistbulk request (4 bytes/entry, no extra syscall). UF_COMPRESSED ⇒ compressed; physical < logical without it ⇒ sparse (block padding goes the other way, so it can never false-positive).
  • FSNode aggregates the gap by causeaggSparseExcess / aggCompressedExcess, two atomics per directory node (~11 MB on a 680k-folder scan), maintained through the parallel scan, SPEC-11 restat, invalidate, file/directory deletion (incl. exact-mode hardlink dedup), and the streamed VM scanner (blocks < bytes ⇒ sparse — the Docker.raw case; ext4 has no transparent compression to confuse it with).
  • SizeDivergence annotates where notable (≥ 1.5× and ≥ 8 MiB over):
    • outline: dashed badge + tooltip "75 MiB on disk · 512 GiB apparent — sparse…"
    • breadcrumb: selection shows both figures
    • stats strip: an apparent stat appears only when the root diverges
    • treemap hover pill and File-types rows (the .ext4 case) get the same tooltip
  • "Apparent" is the du --apparent-size vocabulary — the term the audience can verify in a shell.

Verification

  • 107 tests pass, 4 new: threshold policy, real sparse file (ftruncate), real compressed file (ditto --hfsCompression, UF_COMPRESSED asserted), exact-mode excess dedup across hardlinks.
  • Real-world, the bug's own fixture — headless scan of com.apple.container/snapshots:
    on-disk 1.25 GiB · apparent 1.50 TiB · sparse 1.50 TiB not allocated
  • Compression path/System/Applications/Calculator.app:
    on-disk 3.45 MiB · apparent 5.74 MiB · compressed 2.32 MiB saved
  • GUI verified live on the container directory: snapshots list at their true 529/513/165/75 MiB, strip reads 2.30 GiB total · 2.00 TiB apparent, selection reads 694 MiB · 513 GiB apparent.

Out of scope (deliberate)

  • APFS clone detection (no clean API; expensive).
  • A "Divergence" treemap lens highlighting divergent nodes — natural follow-up if the outline badge proves insufficient for discovery.

…annotation

A global "Logical" toggle re-weighted the whole map by st_size, producing
un-actionable readings on sparse files (three 512 GiB com.apple.container
snapshots occupying ~1.3 GiB; a 2.42 TiB "total" on a 512 GiB volume). The
data was correct; the scope was wrong — nobody needs the apparent size of
the whole disk, but everyone needs it explained where it diverges.

- Everything renders on-disk (allocated blocks): treemap weights, outline,
  totals, file types. SizeMetric and its cache plumbing are gone.
- The scanner requests ATTR_CMN_FLAGS in the same getattrlistbulk call
  (4 bytes/entry, no extra syscall): UF_COMPRESSED tells compressed apart
  from sparse (physical < logical without the flag).
- FSNode aggregates the gap by cause (aggSparseExcess/aggCompressedExcess,
  two atomics per directory) through scan, SPEC-11 restat, invalidate,
  deletions, and the streamed VM scanner (blocks < bytes = sparse).
- SizeDivergence annotates where notable (>= 1.5x and >= 8 MiB over):
  dashed badge + tooltip in the outline, both figures in the breadcrumb,
  an "apparent" stat in the strip, hover pill and File-types tooltips.
  "Apparent" is the du --apparent-size vocabulary.
- Headless scan prints the split; verified against the real snapshots dir
  (1.25 GiB on disk / 1.50 TiB apparent, classified sparse) and a system
  app (compressed). 107 tests pass, 4 new (thresholds, ftruncate sparse,
  ditto --hfsCompression, exact-mode excess dedup).
@github-actions github-actions Bot added the bug Something isn't working label Jul 13, 2026
@rducom
rducom merged commit 0d5d725 into main Jul 13, 2026
6 checks passed
@rducom
rducom deleted the fix/apparent-size-annotation branch July 13, 2026 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant