Files
usenet-indexer/database/migrations/1768620765290_file_details.ts
T
Daan MeijerandClaude Opus 5.5 fad1716d3a
Test and deploy / test (push) Successful in 1m26s
Test and deploy / deploy (push) Successful in 1m54s
Content type and archive listing move from files to file_details
Every probe rewrote its file's row on the HDD (content_type, archive):
a new row version on a random page and an entry in each of the five
indexes. They now live in file_details on the NVMe; files rows are
inserted once. files:move-details copies the existing values after
the deploy; a later migration drops the old columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:36:36 +02:00

29 lines
1.2 KiB
TypeScript

import { BaseSchema } from '@adonisjs/lucid/schema'
/**
* What inspection learns about a file (content type, archive listing) lives
* in file_details, on the NVMe, instead of in `files` (LOG.md 2026-10-08 (14)).
* `files` sits on the HDD and was updated after its insert by every probe:
* a new row version on a random page and an entry in each of its indexes
* (3.7M updates against 49.5M inserts in a day, 27% HOT). Its rows are now
* only inserted (and moved between releases or renamed, rarely).
* The existing values are copied by `files:move-details` after this deploy;
* a later migration drops the columns.
*/
export default class extends BaseSchema {
async up() {
// The foreign key locks `files` briefly: take the lock first, so it can't deadlock with writers.
await this.db.rawQuery(`SET LOCAL lock_timeout = '60s'`)
await this.db.rawQuery(`LOCK TABLE files IN SHARE ROW EXCLUSIVE MODE`)
await this.db.rawQuery(`
CREATE TABLE IF NOT EXISTS file_details (
file_id bigint PRIMARY KEY REFERENCES files (id) ON DELETE CASCADE,
content_type varchar(16),
archive jsonb)`)
}
async down() {
await this.db.rawQuery(`DROP TABLE IF EXISTS file_details`)
}
}