fix(downloads): atomic ref_count increment/decrement (E3 S2, B-sub-5)

MediaAsset.ref_count (how many jobs hold a shared cache asset) was a Python
read-modify-write at four sites (enqueue, enqueue_edit, release_asset, the
redownload route). Two concurrent enqueues of the same (source,format) both read
the same value and write the same +1 → the count ends up one short → the first
release drives it to zero and deletes the file out from under a live holder.

Replace all four with atomic DB ops: incr_ref_count (`ref_count = ref_count + 1`)
and decr_ref_count (`greatest(ref_count - 1, 0)` RETURNING the new value, so the
release decides whether to free the asset from the post-decrement count while
holding the row's write lock — Postgres serialises concurrent releases on that
lock, closing the double-free). Pure DB-atomicity change, no semantic shift.

Green under the E3 S2 ref_count net (5) + full lane (356 pass), ruff clean.
This commit is contained in:
2026-08-18 21:27:39 +02:00
parent e824fe0ae9
commit f0a0214d97
2 changed files with 33 additions and 5 deletions
+1 -1
View File
@@ -523,7 +523,7 @@ def redownload_download(
# last holder (a co-held asset is left intact for its other holders).
service.release_asset(db, job)
asset.ref_count = (asset.ref_count or 0) + 1
service.incr_ref_count(db, asset.id)
job.asset_id = asset.id
job.status = "queued"
job.progress = 0