-- name: UpsertTrackFingerprint :exec -- Written whenever a track's fingerprint is derived: by the scan when a file is -- new or its bytes changed, and by the backfill (#3908) for rows derived by an -- older method. Replaces the row wholesale — a fingerprint of the old bytes has -- no standing once the file has changed. INSERT INTO track_fingerprints ( track_id, audio_stream_sha256, chromaprint, fingerprint_version ) VALUES ( sqlc.arg(track_id), sqlc.narg(audio_stream_sha256), sqlc.narg(chromaprint), sqlc.arg(fingerprint_version) ) ON CONFLICT (track_id) DO UPDATE SET audio_stream_sha256 = EXCLUDED.audio_stream_sha256, chromaprint = EXCLUDED.chromaprint, fingerprint_version = EXCLUDED.fingerprint_version, computed_at = now(); -- name: DeleteTrackFingerprint :exec -- A file changed but could not be fingerprinted, for a reason unrelated to the -- file. The stored row describes the OLD bytes, so it goes and the backfill -- re-derives it — nothing may keep trusting a stale identity. DELETE FROM track_fingerprints WHERE track_id = $1; -- name: ListTracksNeedingFingerprint :many -- The backfill's work queue (#3908): tracks with no fingerprint, or one derived -- by an older method. Keyset-paged on id so a pass visits each track at most -- once. That cursor is load-bearing: an inconclusive attempt writes no row, so -- without it a file that keeps timing out would be listed again straight away -- and retried in a tight loop. Missing tracks are skipped — there is no file to -- read. SELECT t.id, t.file_path FROM tracks t LEFT JOIN track_fingerprints f ON f.track_id = t.id WHERE t.missing_since IS NULL AND (f.track_id IS NULL OR f.fingerprint_version < sqlc.arg(current_version)) AND t.id > sqlc.arg(after_id) ORDER BY t.id LIMIT sqlc.arg(batch_limit); -- name: GetFingerprintCoverage :one -- The admin gauge for the backfill. fingerprinted + rejected + pending = total. -- rejected is a row at the current version with a NULL half: a tool ran and -- refused the file, which is settled rather than waiting. Missing tracks are -- excluded, or the gauge could never reach the end. SELECT count(*)::bigint AS total, count(*) FILTER ( WHERE f.fingerprint_version >= sqlc.arg(current_version) AND f.audio_stream_sha256 IS NOT NULL AND f.chromaprint IS NOT NULL )::bigint AS fingerprinted, count(*) FILTER ( WHERE f.fingerprint_version >= sqlc.arg(current_version) AND (f.audio_stream_sha256 IS NULL OR f.chromaprint IS NULL) )::bigint AS rejected, count(*) FILTER ( WHERE f.track_id IS NULL OR f.fingerprint_version < sqlc.arg(current_version) )::bigint AS pending FROM tracks t LEFT JOIN track_fingerprints f ON f.track_id = t.id WHERE t.missing_since IS NULL;