Files
Oxicloud/src/infrastructure
Edouard Vanbelle ea5d3003e0 fix(dedup): bulk manifest reap orphaned every derived row
Real leak, found by storage_cleanup_check.sh: three blobs surviving a
full teardown, all `derived=1`, all naming one `src` whose manifest,
blob row and files were already gone. The source had been reaped without
its derived rows being purged.

`reap_blob` purges correctly for the single-blob path. The BULK manifest
reap did not — it iterated the deleted batch only to invalidate the
manifest cache, so every manifest reaped that way left its
content_derived_blobs rows behind.

The predicate is not at fault. It protects a manifest that IS a derived
artifact (content_derived_blobs.blob_hash) and deliberately not one that
is the SOURCE of them, because counting source_hash as a reference would
pin every original for as long as a thumbnail existed. The source is
therefore reaped correctly and the purge simply has to follow it.

The consequence is permanent, not cosmetic: the orphaned row holds
chunk_manifests.ref_count at 1 on the thumbnail's own blob, so GC is
thereafter CORRECT to refuse it — which is why three passes with
force=true reclaimed nothing. Every deleted image left three behind, one
per size, growing forever.

Fixed at the reap rather than in any deletion path, which is where all
of them converge: folder cascade, drive deletion, user deletion and
single-file delete all reach it through the decrement trigger, so one
call covers every route.
2026-08-30 13:41:05 +02:00
..
2026-07-27 22:05:08 +02:00