test(api): diagnose all leftovers, and name the pinning source
The run gave the decisive fact: `derived=1`. A content_derived_blobs row still points at the leftover blob, so GC is CORRECT to keep it — the leak is the row, not the bytes. purge_derived_blobs only runs when the SOURCE is reaped, so the question is why that never happened. So the dump now prints the source hash and what still holds it: src_files, src_manifest, src_blob. If the source has a live file the answer is "not deleted"; if it has none but a positive refcount, a release was missed upstream; if it has no row at all, the source was reaped WITHOUT purging, which would be a real ordering bug in reap_blob. Also fixes the dump reporting only one of three blobs. `docker compose exec -T` reads stdin, so it consumed the rest of the here-string feeding the loop — the other two were never queried and vanished silently. The same silent-truncation shape the diagnosis exists to expose, in the diagnosis. `< /dev/null` closes it.
This commit is contained in:
@@ -447,8 +447,21 @@ if [[ -n "$BLOB_FILES" ]]; then
|
||||
|| ' blob_refs=' || COALESCE((SELECT ref_count::text FROM storage.blobs WHERE hash='$h'), '-')
|
||||
|| ' files=' || (SELECT count(*) FROM storage.files WHERE blob_hash='$h')
|
||||
|| ' derived=' || (SELECT count(*) FROM storage.content_derived_blobs WHERE blob_hash='$h')
|
||||
|| ' attached=' || (SELECT count(*) FROM storage.file_attached_blobs WHERE blob_hash='$h');" \
|
||||
|| ' attached=' || (SELECT count(*) FROM storage.file_attached_blobs WHERE blob_hash='$h')
|
||||
-- When a derived row is what pins the blob, the question is
|
||||
-- why its SOURCE was never reaped — purge_derived_blobs only
|
||||
-- runs from the source's reap. Print the source and whether
|
||||
-- anything still holds it.
|
||||
|| COALESCE((SELECT ' src=' || d.source_hash
|
||||
|| ' src_files=' || (SELECT count(*) FROM storage.files WHERE blob_hash = d.source_hash)
|
||||
|| ' src_manifest=' || COALESCE((SELECT ref_count::text FROM storage.chunk_manifests WHERE file_hash = d.source_hash), '-')
|
||||
|| ' src_blob=' || COALESCE((SELECT ref_count::text FROM storage.blobs WHERE hash = d.source_hash), '-')
|
||||
FROM storage.content_derived_blobs d WHERE d.blob_hash='$h' LIMIT 1), '');" \
|
||||
< /dev/null \
|
||||
2> >(grep -v 'Executing external compose provider' >&2) || true
|
||||
# `< /dev/null`: `docker compose exec -T` reads stdin, and without this it
|
||||
# consumes the rest of the here-string — so only the FIRST leftover was
|
||||
# ever diagnosed and the others vanished silently.
|
||||
done <<< "$BLOB_FILES"
|
||||
|
||||
log "Leftover blob files ($BLOB_COUNT):"
|
||||
|
||||
Reference in New Issue
Block a user