Files
usenet-indexer/database/migrations/1770000006800_pending_classes.ts
T
Daan MeijerandClaude Fable 5.1 44c0c73b05
Test and deploy / test (push) Successful in 3m9s
Test and deploy / deploy (push) Successful in 40m8s
Pending ladder by class, twins by content, dropped classes at the edge
The prober names 6% of the unnamed releases it finishes and the pending
queue (44M) grows eleven times faster than it probes. A sample of 44,530
finished pending rows shows the headers predict a name: size bucket, name
shape, completeness, tool and group separate 0% classes from 95% ones,
while the learner keyed on tool and group alone (LOG.md (130)).

- lib/release/classes.ts, names::pending_class, SQL pending_class():
  a release's class (size × shape × partial, 1..70), the three in step.
- Migration 6800: pending_releases.klass and target_bytes (the first
  target's article; candidates carry bytes now), pending_classes with
  each class's climbs, names, waiting and verdict, the claim's index.
- The ladder claims the classes with the best record first (a prior for
  the unexplored, at most a quarter of a claim from one), the cheapest
  target first within one, then the oldest of the rest; records classes
  like signatures and drops them at the same thresholds; discards their
  waiting releases. Claimed rows sorted in code: an UPDATE returns none.
- The rule set's droppedClasses: the edge keeps unnamed releases of a
  dropped class out of the pending store (counted as garbage), the
  explored sample excepted.
- hash_twins.ts: a probed file whose first 16 KiB and size match a named
  catalog release's names a pending release the probe didn't, and sets
  the inner name of a catalog release without one.
- pending:classes classes the rows from before and seeds the record from
  the finished ones; rules:classes publishes the dropped classes;
  releases:readable also marks the rows' candidates unreadable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 12:22:32 +01:00

58 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { BaseSchema } from '@adonisjs/lucid/schema'
/**
* The pending ladder by class (REBUILD.md decision f; LOG.md (130)): a pending release's class (lib/release/classes.ts:
* size bucket × name shape × partial, 1..70; 0 for rows from before) and the bytes of its first target, so the
* claim takes the classes with the best record first and the cheapest article within one; pending_classes per
* (tool, group, class) how many climbed to the end and how many got a name, `waiting` how many wait (kept by the
* batch store, the claim and the discard; recounted by pending:classes), `dropped` as pending_signatures.
* The SQL pending_class() is the TypeScript's pendingClass, for the batch store's insert and the backfill.
*/
export default class extends BaseSchema {
static disableTransactions = true
async up() {
this.schema.raw(`
CREATE OR REPLACE FUNCTION pending_class(name text, bytes bigint, partial boolean) RETURNS smallint LANGUAGE sql IMMUTABLE AS $$
SELECT ((CASE WHEN bytes < 1000000 THEN 0 WHEN bytes < 10000000 THEN 1 WHEN bytes < 100000000 THEN 2 WHEN bytes < 1000000000 THEN 3 ELSE 4 END) * 14
+ (CASE WHEN s ~ '^[0-9a-fA-F]{16,}$' THEN 1
WHEN s ~ '^[0-9]{6,}$' THEN 2
WHEN s ~ '^[a-z2-7]{20,}$' AND s ~ '[2-7]' THEN 3
WHEN s ~ '^[A-Za-z]+$' THEN 4
WHEN s ~ '^[A-Za-z0-9]+$' THEN 5
WHEN s ~ '^[A-Za-z0-9._-]+$' THEN 6
ELSE 7 END - 1) * 2
+ (CASE WHEN partial THEN 1 ELSE 0 END) + 1)::smallint
FROM (SELECT regexp_replace(name, '\\.[A-Za-z0-9]{1,4}$', '') AS s) x
$$`)
this.schema.raw(
`ALTER TABLE pending_releases ADD COLUMN IF NOT EXISTS klass smallint NOT NULL DEFAULT 0`
)
this.schema.raw(`ALTER TABLE pending_releases ADD COLUMN IF NOT EXISTS target_bytes bigint`)
this.schema.raw(`
CREATE TABLE IF NOT EXISTS pending_classes (
tool varchar(16) NOT NULL,
group_id integer NOT NULL,
klass smallint NOT NULL,
probed integer NOT NULL DEFAULT 0,
named integer NOT NULL DEFAULT 0,
waiting integer NOT NULL DEFAULT 0,
dropped boolean NOT NULL DEFAULT false,
updated_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (tool, group_id, klass)
)`)
// The claim by class: the cheapest target first within one, the oldest among equals.
this.schema.raw(
`CREATE INDEX CONCURRENTLY IF NOT EXISTS pending_releases_class_idx ON pending_releases (tool, group_id, klass, target_bytes, created_at) WHERE status = 0`
)
}
async down() {
this.schema.raw(`DROP INDEX CONCURRENTLY IF EXISTS pending_releases_class_idx`)
this.schema.raw(`DROP TABLE IF EXISTS pending_classes`)
this.schema.raw(`ALTER TABLE pending_releases DROP COLUMN IF EXISTS target_bytes`)
this.schema.raw(`ALTER TABLE pending_releases DROP COLUMN IF EXISTS klass`)
this.schema.raw(`DROP FUNCTION IF EXISTS pending_class(text, bigint, boolean)`)
}
}