Skip to content

fix(engine): never orphan files, and reclaim orphans under the disk cap#3

Merged
jodacame merged 1 commit into
mainfrom
fix/disk-orphans
Jul 1, 2026
Merged

fix(engine): never orphan files, and reclaim orphans under the disk cap#3
jodacame merged 1 commit into
mainfrom
fix/disk-orphans

Conversation

@jodacame

@jodacame jodacame commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Problema

Podían quedar archivos huérfanos: "borrado del listado pero sigue en disco". Dos huecos:

  1. deleteRecordFiles huerfanizaba en fallo. El defer borraba el record aunque el RemoveAll fallara o el nombre fuera inseguro → archivos sin record.
  2. El tope iteraba records, así que archivos sin record (de un rem, un borrado sin archivos, o históricos) eran invisibles → nunca se recuperaban.

Arreglo

  1. No huerfanizar: el record se borra solo cuando los archivos se eliminaron de verdad. Si falla o el nombre es inseguro → se mantiene el record (rastreado, se reintenta).
  2. Reconciliación por sistema de archivos: enforceDiskCap ahora escanea /downloads, protege lo respaldado por un torrent activo/seed vivo, y desaloja lo más viejo primero — records y huérfanos — hasta bajar del tope.
  3. TorrServer rem ahora retira el torrent (limpieza en el ciclo normal) en vez de borrar el record y dejar los archivos.

Seguridad

  • El desalojo re-verifica que la entrada no esté activa y que la ruta quede dentro de la caché.
  • Como el tope recupera cualquier archivo inactivo de la carpeta, el README avisa de no apuntar FT_CACHE_PATH a una carpeta compartida con otras apps.

Verificación

  • Tests nuevos: KeepsRecordOnFailure (no huerfaniza) y ScanDiskFindsOrphans. Backend build+vet+test verde.
  • En vivo: con tope de 1 GB y un huérfano de 1.2 GB (sin record) → el janitor lo elimina: disk cap: evicted orphan (orphan-big), freed 1200MB, /downloads queda vacío.

🤖 Generated with Claude Code

Two gaps in the disk-retention logic let files survive on disk with nothing
tracking them ("removed from the listing but still on disk"):

1. deleteRecordFiles dropped the record via a deferred call even when the actual
   file removal was refused (unsafe name) or failed (I/O) — orphaning the files.
   Now the record is dropped ONLY after the files are confirmed gone; a failed or
   refused removal keeps the record so the files stay tracked and get retried.

2. The disk cap iterated records, so files with no record (a client "rem", a
   delete-without-files, or leftovers from a past run) were invisible and never
   reclaimed. enforceDiskCap now reconciles against the actual download folder:
   it lists on-disk entries, protects those backed by an active/seeding torrent,
   and evicts the oldest inactive item first — records AND untracked orphans —
   until back under Disk.MaxGB.

Also: TorrServer "rem" now retires the torrent (cleaned on the normal schedule)
instead of deleting the record and leaving the files behind untracked.

Safety: eviction re-checks the entry isn't active and stays inside the cache dir.
Because the cap reclaims any inactive file under the folder, README warns not to
point FT_CACHE_PATH at a folder shared with other apps.

Tests: keeps-record-on-failure, scanDisk orphan detection.
Verified live: a 1.2 GB orphan (no record) is evicted under a 1 GB cap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012bj3G2zzqEaALFa8ufbkDJ
@jodacame
jodacame merged commit db09aff into main Jul 1, 2026
2 checks passed
@jodacame
jodacame deleted the fix/disk-orphans branch July 1, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant