matchPar2Releases checked every same-size release_files row's set and date (18 s per batch of body-derived binaries); now an index on release_files (release_id, size) drops the repeated sizes first: 0.16 s. File inserts updated their release in four row triggers; one statement trigger now updates each release once per INSERT. Completeness is noted in release_dirty and recomputed by gc:scheduler every 30 minutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
36 lines
1.4 KiB
TypeScript
36 lines
1.4 KiB
TypeScript
import db from '@adonisjs/lucid/services/db'
|
|
|
|
/** Noted releases taken per transaction. */
|
|
const BATCH = 2000
|
|
|
|
/**
|
|
* Release completeness (D24) for releases whose files or par2 listing
|
|
* changed: triggers only note them in release_dirty (a release can be noted
|
|
* thousands of times between sweeps), and gc:scheduler recomputes each
|
|
* noted release once every RELEASE_COMPLETE_INTERVAL_MS (LOG.md 2026-10-06 (6)).
|
|
*/
|
|
class ReleaseCompleteness {
|
|
/** Recomputes all noted releases; returns how many distinct releases were checked. */
|
|
async sweep(): Promise<number> {
|
|
let checked = 0
|
|
for (;;) {
|
|
const done = await db.transaction(async (trx) => {
|
|
// Taken and recomputed in one transaction: a failure leaves the notes for the next sweep.
|
|
const { rows } = await trx.rawQuery(
|
|
`DELETE FROM release_dirty WHERE ctid = ANY(ARRAY(SELECT ctid FROM release_dirty LIMIT ?)) RETURNING release_id`,
|
|
[BATCH]
|
|
)
|
|
const ids: number[] = [...new Set<number>(rows.map((row: { release_id: string }) => Number(row.release_id)))]
|
|
if (ids.length > 0) {
|
|
await trx.rawQuery(`SELECT recompute_release_complete(id) FROM unnest(?::bigint[]) AS id`, [ids])
|
|
}
|
|
checked += ids.length
|
|
return rows.length < BATCH
|
|
})
|
|
if (done) return checked
|
|
}
|
|
}
|
|
}
|
|
|
|
export default new ReleaseCompleteness()
|