pub async fn mark_reaped(conn: &mut PgConnection, id: Uuid) -> ModelResult<bool>Expand description
Retires an upload, keeping the row so a submit naming it answers upload_expired instead of
the misleading unknown_upload. Idempotent, so a run retrying a failed object delete can call
it again.
Re-checks that no submission has come to reference the upload since get_reapable listed it,
and reports false if one has. That re-check plus the row lock
lock_for_exercise_and_user takes is what stops a reap from landing in the middle of a
submit and destroying its files.
The lock is taken in a statement of its own, and that ordering is the whole point. Under READ
COMMITTED a statement’s snapshot is fixed when the statement starts, and Postgres refreshes only
the row an UPDATE locks — never the rows its subqueries read. So a single locking UPDATE
blocks on the submit’s lock, unblocks, and then evaluates NOT EXISTS against a snapshot from
before the submit committed: it finds no submission and reaps the files of a submission that
already answered 200. Locking first makes the UPDATE a later statement, so its snapshot
includes that commit.