Skip to content

-q keeps the per-pass report noise and suppresses the summary #148

Description

@martinus

What problem would this solve?

-q is documented as "print only errors and a one-line summary", and it is the mode the shipped systemd/[email protected] runs (ExecStart=/usr/bin/oans --quiet --hashfile=..., commented "keeps the journal to a short summary"). In practice it does close to the opposite: it keeps per-pass noise and suppresses the summary.

1. Report mode prints two lines per generation pass.

print_dupes_table() in src/run_dedupe.c emits its "Simple read and compare of file data found %u instances of %s" header before the if (quiet || res->num_dupes == 0) return; guard a few lines below. It's called once per pass per kind, so a multi-generation scan prints 2×N lines — including ones reporting zero:

$ oans -rq --hashfile=/tmp/h.db ~/git
Simple read and compare of file data found 1513 instances of files that might benefit from deduplication.
Simple read and compare of file data found 2 instances of extents that might benefit from deduplication.
Simple read and compare of file data found 2864 instances of files that might benefit from deduplication.
Simple read and compare of file data found 5 instances of extents that might benefit from deduplication.
Simple read and compare of file data found 342 instances of files that might benefit from deduplication.
Simple read and compare of file data found 15 instances of extents that might benefit from deduplication.

Six lines, none of which is a summary, and the counts are per-pass so they don't even sum to anything a user would want.

2. The real summary is suppressed by -q — including the failure line.

run_dedupe.c:~1176 gates the whole Summary block on if (!quiet). That block is the only place Reclaimed, Not deduped … N changed since scan, N failed, and Already shared are ever printed. So the quiet mode used by the unattended timer is precisely the mode that hides the dedupe failure counters.

3. The one line -q does print in dedupe mode is the wrong number.

Three 5 MB copies, of which two are reclaimable:

$ oans -rdq --hashfile=/tmp/h.db /scratch/qprobe
Comparison of extent info shows a net change in shared extents of: 15000000

Non-quiet mode reports Reclaimed 9.5 MiB for the same run. The quiet line is the fiemap diagnostic, which counts the surviving copy too (≈2× for pairs, 3× here) — a known quirk, already documented in CLAUDE.md, but -q is exactly where scripts and journals read it. It's also raw bytes with no unit. Someone logging quiet output weekly is recording a number ~1.5–2× the space actually freed.

Proposed solution

Make -q mean what it says.

  • Move the printf in print_dupes_table() below the quiet guard so the per-pass header is suppressed like the table it heads. One-line fix.
  • Print the Summary block under -q, either in full or condensed to a genuine one-liner, e.g.
    oans: reclaimed 9.5 MiB across 3 groups in 1.2s
  • Always print the failure lines under -qNot deduped … N failed and the scan-side skip counts from Scan-phase skips and errors are never counted, reported, or exported #145 are "errors", which quiet's own contract promises to keep.
  • Report Reclaimed, not the fiemap delta, as the quiet one-liner, formatted with human_size() like everywhere else. If the fiemap delta is worth keeping as a diagnostic, it belongs behind -v, not in the mode designed for logs.

Worth deciding together: whether -q should stay a human one-liner given --progress=json and --json already serve machines. I think yes — the journal is read by humans — but that argues for the condensed form above rather than the full multi-line block.

Alternatives considered

  • Point users at --progress=json. Different job: it's a stderr JSONL progress stream for a live UI, not an end-of-run summary, and it doesn't cover the scan-side skips at all.
  • Point users at --json. Reports on the hashfile, in a separate invocation, and adds a jq dependency for what should be one readable journal line.
  • Change the systemd unit to drop --quiet. Makes the journal much noisier for every user and leaves -q broken for everyone driving oans from a script.
  • Leave the fiemap number and document it. It's already documented in CLAUDE.md and it's still the wrong figure to hand an unattended logger; the honest Reclaimed value exists and is already computed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions