46 lines
2.4 KiB
TypeScript
46 lines
2.4 KiB
TypeScript
import { BaseSchema } from '@adonisjs/lucid/schema'
|
|
|
|
/**
|
|
* Final completeness by time window (LOG.md 2026-10-16 (67)). A release settles once quiet, but history is read
|
|
* newest first and in islands: one next to an unread range was "incomplete" twice as often (52.5% against 25.7%),
|
|
* its missing files only not read yet. An upload is posted within hours, so a release is final (its complete verdict
|
|
* definite) once done ranges cover its posting times and FINAL_MARGIN either side.
|
|
* - ranges.posted_low/high: the posting time span the workers report per batch (postedSpan: without the earliest and
|
|
* latest 1%), the min and max over the range's batches.
|
|
* - range_blocks: runs of consecutive done ranges per group with their span (RangeBlocks rebuilds it); at_group_start
|
|
* when the run starts at the group's first range (nothing older to wait for).
|
|
* - release_final(): whether one block holds the release's articles and reaches FINAL_MARGIN past its posting times.
|
|
* Computed when asked, so no release row is written (50M updates would double the table on the NVMe).
|
|
*/
|
|
export default class extends BaseSchema {
|
|
async up() {
|
|
this.schema.raw(`ALTER TABLE ranges ADD COLUMN IF NOT EXISTS posted_low timestamptz, ADD COLUMN IF NOT EXISTS posted_high timestamptz`)
|
|
this.schema.raw(`
|
|
CREATE TABLE range_blocks (
|
|
group_id integer NOT NULL,
|
|
start_id bigint NOT NULL,
|
|
end_id bigint NOT NULL,
|
|
posted_low timestamptz,
|
|
posted_high timestamptz,
|
|
at_group_start boolean NOT NULL,
|
|
PRIMARY KEY (group_id, start_id)
|
|
)`)
|
|
// FINAL_MARGIN: 6 hours.
|
|
this.schema.raw(`
|
|
CREATE FUNCTION release_final(g integer, first_article bigint, last_article bigint, posted timestamptz, last_posted timestamptz)
|
|
RETURNS boolean LANGUAGE sql STABLE AS $$
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM range_blocks b
|
|
WHERE b.group_id = g AND b.start_id <= first_article AND b.end_id >= last_article
|
|
AND (b.at_group_start OR b.posted_low <= posted - interval '6 hours')
|
|
AND b.posted_high >= coalesce(last_posted, posted) + interval '6 hours')
|
|
$$`)
|
|
}
|
|
|
|
async down() {
|
|
this.schema.raw(`DROP FUNCTION IF EXISTS release_final(integer, bigint, bigint, timestamptz, timestamptz)`)
|
|
this.schema.raw(`DROP TABLE IF EXISTS range_blocks`)
|
|
this.schema.raw(`ALTER TABLE ranges DROP COLUMN IF EXISTS posted_low, DROP COLUMN IF EXISTS posted_high`)
|
|
}
|
|
}
|