/** * Write-ahead journal for crash-atomic, multi-file commits. * * A transaction writes its intent to `journal.jsonl` (fsynced) before touching * any live file, then swaps each live file aside (see `backup`), renames the * freshly-written temp file into place, optionally renames the pagination * metadata file, and finally appends a `commit` marker (fsynced). * * Two journal layouts share one recovery rule: * - single-table ops: one `begin` entry carrying `files` + `pagination`; * - database transactions: a `begin` entry (tables only) followed by one `op` * entry per staged mutation (`files` + optional `pagination`), then `commit`. * * Recovery rule (run under the lock before any access): * - journal without `commit` -> roll back (restore backups, undo pagination, * discard temps); * - journal with `commit` -> roll forward (complete swaps, discard backups). * * After recovery the journal is removed, so a logical operation spanning many * column files + pagination (single- or multi-table) is atomic w.r.t. crashes. */ export interface JournalFileOp { /** Absolute path of the live file being replaced or removed. */ live: string; /** Absolute path where the original file is parked while the swap is in flight. */ backup: string; /** Absolute path of the fully-written replacement, or null for pure removals. */ tmp: string | null; /** Whether the live file existed when the transaction began. */ existed: boolean; } export interface JournalBeginEntry { txn: string; type: "begin"; /** Tables touched by a database transaction (single-table ops omit this). */ tables?: string[]; /** Single-table ops carry their intent directly on the begin entry. */ files?: JournalFileOp[]; /** Old/new absolute pagination file paths, or null when counts don't change. */ pagination?: { from: string; to: string; } | null; } export interface JournalOpEntry { txn: string; type: "op"; files: JournalFileOp[]; /** Old/new absolute pagination file paths, or null when counts don't change. */ pagination?: { from: string; to: string; } | null; } export interface JournalCommitEntry { txn: string; type: "commit"; } export type JournalEntry = JournalBeginEntry | JournalOpEntry | JournalCommitEntry; export declare class Journal { readonly path: string; private readonly txn; private handle; constructor(tablePath: string, txn: string); private openJournal; private append; begin(files: JournalFileOp[], pagination?: JournalBeginEntry["pagination"]): Promise; commit(): Promise; /** * Undo an in-flight transaction whose `commit` marker was never written. * Restores originals from backups, undoes the pagination rename (if any), * removes created files and leftovers, then discards the journal. */ rollback(): Promise; dispose(): Promise; } /** * Write-ahead journal for a database-level transaction spanning multiple * tables. Holds `begin(tables)` once, then one `op` per staged mutation, and * finally a single `commit` marker. Lives in `/.tmp/journal.jsonl` * next to the per-table `.tmp` directories. */ export declare class DatabaseJournal { readonly path: string; private readonly txn; private handle; constructor(dbPath: string, txn: string); private openJournal; private append; begin(tables: string[]): Promise; op(files: JournalFileOp[], pagination?: JournalOpEntry["pagination"]): Promise; commit(): Promise; /** * Undo the transaction: restore any published files (crash mid-commit in * the same process — callers normally roll back before anything is * published), discard temps/journals. Handles the un-published case * identically (no backups exist -> restores are no-ops). */ rollback(): Promise; dispose(): Promise; } /** * Recover from a crash. `tmpDirPath` is a `.tmp` directory (a table's or the * database's) where `journal.jsonl` lives, in either single-table or * database-transaction layout. Entries carry absolute paths, so no other * context is needed. Must be called while holding the corresponding lock so no * live writer can interleave. */ export declare function recover(tmpDirPath: string): Promise;