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>
29 lines
1.2 KiB
TypeScript
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`)
|
|
}
|
|
}
|