trees: the reclaimable total counts a duplicate tree twice when it lies inside another reported one #168

Closed
opened 2026-11-11 01:02:55 +01:00 by clawbot · 3 comments
Collaborator

Defect, found in the acceptance test (#164) on next at 202f083.

Steps

make build
d=$(mktemp -d /var/tmp/sfdupes.XXXXXX)
export SFDUPES_DATABASE="$(mktemp -d /var/tmp/sfdupes.XXXXXX)/db.sqlite"
mkdir -p "$d/A/x" "$d/A/y" "$d/B/x" "$d/B/y" "$d/C/x"
dd if=/dev/urandom of="$d/A/x/f" bs=1000 count=1 status=none
dd if=/dev/urandom of="$d/A/y/g" bs=500 count=1 status=none
cp "$d/A/x/f" "$d/B/x/f"
cp "$d/A/y/g" "$d/B/y/g"
cp "$d/A/x/f" "$d/C/x/f"
./sfdupes scan "$d"
./sfdupes trees

What happened

first	dupe	files	size	disk_size
$d/A	$d/B	2	1500	1024
$d/A/x	$d/B/x	1	1000	512
$d/A/x	$d/C/x	1	1000	512
trees: 5 records read, 2 duplicate tree groups, 3 dupe trees, 3.4 KiB reclaimable

The total is 3500 bytes. Removing every dupe path (B, B/x, C/x) frees 2500 bytes: B/x lies inside B, and its 1000 bytes are counted in both rows.

On the acceptance tree of about 4000 files the total read 7.5 MiB, where removing every dupe path frees 5.7 MiB.

Why it matters

The total is the number a user reads to decide whether a cleanup is worth doing. It is too high whenever a subtree has a copy outside two otherwise identical parents, which is common in backup trees.

What should happen

  • The total is what removing every dupe path in the report would free, by the recorded sizes: each recorded file at or below a dupe path is counted once.
  • The rows stay as they are.
  • README.md ("Trees output format") defines the total as "the sum of size over all rows". The code follows that sentence, so the sentence changes with the code.

Model: fable-5-2

Defect, found in the acceptance test (https://git.eeqj.de/sneak/sfdupes/issues/164) on `next` at `202f083`. ## Steps ```sh make build d=$(mktemp -d /var/tmp/sfdupes.XXXXXX) export SFDUPES_DATABASE="$(mktemp -d /var/tmp/sfdupes.XXXXXX)/db.sqlite" mkdir -p "$d/A/x" "$d/A/y" "$d/B/x" "$d/B/y" "$d/C/x" dd if=/dev/urandom of="$d/A/x/f" bs=1000 count=1 status=none dd if=/dev/urandom of="$d/A/y/g" bs=500 count=1 status=none cp "$d/A/x/f" "$d/B/x/f" cp "$d/A/y/g" "$d/B/y/g" cp "$d/A/x/f" "$d/C/x/f" ./sfdupes scan "$d" ./sfdupes trees ``` ## What happened ``` first dupe files size disk_size $d/A $d/B 2 1500 1024 $d/A/x $d/B/x 1 1000 512 $d/A/x $d/C/x 1 1000 512 trees: 5 records read, 2 duplicate tree groups, 3 dupe trees, 3.4 KiB reclaimable ``` The total is 3500 bytes. Removing every `dupe` path (`B`, `B/x`, `C/x`) frees 2500 bytes: `B/x` lies inside `B`, and its 1000 bytes are counted in both rows. On the acceptance tree of about 4000 files the total read 7.5 MiB, where removing every `dupe` path frees 5.7 MiB. ## Why it matters The total is the number a user reads to decide whether a cleanup is worth doing. It is too high whenever a subtree has a copy outside two otherwise identical parents, which is common in backup trees. ## What should happen - The total is what removing every `dupe` path in the report would free, by the recorded sizes: each recorded file at or below a `dupe` path is counted once. - The rows stay as they are. - `README.md` ("Trees output format") defines the total as "the sum of `size` over all rows". The code follows that sentence, so the sentence changes with the code. Model: fable-5-2
Owner

yes, this is a bug, fix it

yes, this is a bug, fix it
Author
Collaborator

sneak (11 November, about 02:25 UTC): a bug; fix it. The reclaimable total counts each duplicate tree once, never again when it lies inside another reported tree; a test covers a nested pair.

Model: opus-5-5

sneak (11 November, about 02:25 UTC): a bug; fix it. The reclaimable total counts each duplicate tree once, never again when it lies inside another reported tree; a test covers a nested pair. Model: opus-5-5
Author
Collaborator

Fixed in #188: the reclaimable total skips a dupe tree that lies inside another dupe tree. The rows are unchanged, and the README defines the total to match. The steps above now report 2.4 KiB (2500 bytes).

Model: opus-5-5

Fixed in https://git.eeqj.de/sneak/sfdupes/pulls/188: the reclaimable total skips a dupe tree that lies inside another dupe tree. The rows are unchanged, and the README defines the total to match. The steps above now report 2.4 KiB (2500 bytes). Model: opus-5-5
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/sfdupes#168