Repository navigation
Conversation
An APFS clone reports every block it shares with its family in st_blocks, so three copies of 200 MB read as 600 MB and marking one projected a saving that deleting it never gives back. - The macOS listing asks getattrlistbulk for each file's clone id, clone count and sharing flags. A clone family is charged once, keyed apart from inode numbers, so totals match the disk. - Node gains `unshared` (88 -> 96 bytes): the part of a subtree no other file shares. Projections, the delete dialog and "Worth a look" count only that; the shared remainder is said, not claimed. - Private size is read per file only for copies edited away from their family and larger than 64 KiB: asking it of every file doubled scan time on a 3.1 million file ~/Library. - Older kernels that refuse the newer attributes are asked again with less, and a followed symlink is charged as its family too. On a clone-heavy ~/Library the total drops from 309.2 GB to 294.3 GB; the scan takes about 13% longer (14.1 s to 16.0 s, 8 workers).
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
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
An APFS clone (
cp -c, Finder's Duplicate) reports every block it shares with its family inst_blocks. So:~/Library(3.1M files) the scan reported 309.2 GB; the correct figure is 294.3 GB.Fix
macos.rs):getattrlistbulknow also asks forATTR_CMNEXT_CLONEID,ATTR_CMNEXT_CLONE_REFCNTandATTR_CMNEXT_EXT_FLAGS. Every member of a clone family is charged under one identity (the clone id, tagged so it can't collide with an inode number), so the existing hardlink de-duplication counts the family once.Node::unshared: the part of a subtree no other file shares, derived bottom-up likebytes. Whole clones hold 0 of their own. The review projection, the delete dialog ("This frees …") and Worth a look now count only unshared bytes. The shared remainder is shown as "N shared with clones" under Not counted here.ATTR_CMNEXT_PRIVATESIZE, which costs an extent walk per file. It is fetched per file, only for those over 64 KiB.EINVALare asked again with fewer attributes; the fallback is remembered. A file reached through a followed symlink is charged as its clone family too.Cost
Nodegrows from 88 to 96 bytes (a_node_stays_smallupdated): about 80 MB more for a 10M-node scan.~/Library, 8 workers, 6 alternating runs: 14.1 s → 16.0 s (≈+13%). A disk with few clones pays close to nothing.PRIVATESIZEof every file instead doubled scan time (15 s → 31 s), which is why it is fetched per file.Known limits (documented)
statvfsresult after removal shows the real number.~/Library: 195k such files, 1.4 GB allocated between them).Tests
macos.rs: a clone family shares one identity and holds nothing of its own; an edited copy leaves the family and holds only what was written; a single-pathstatreads the same as the listing (including through symlinks); a refused attribute request is retried with fewer attributes, and other errors are not.scan.rs: a family is charged once, once per copy with de-duplication off, and once again through a followed link.tree.rs,removal.rs,insights.rs,marks.rs:unsharedis derived and charged once; the plan projects only unshared bytes and reports the shared part.cp -cclone is scanned and marked, the projection and the shared figure are checked, and the review screen and delete dialog are drawn.EINVALfallback each fails a test.cargo xtask lintpasses.cargo xtask testpasses exceptenter_in_the_focused_volume_picker_scans_the_selected_root, which fails identically onmainon macOS (/private/varvs/varpaths).disktree-coreclippy is also clean when cross-checked for Linux and for Windows (the Windows library; its test target has two dead-code errors inremote.rsthatmainhas too).