@bobfrankston/rmfmail 1.2.9 → 1.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/mailx-service/index.d.ts +1 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +19 -1
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +18 -0
- package/packages/mailx-store/db.d.ts +11 -0
- package/packages/mailx-store/db.d.ts.map +1 -1
- package/packages/mailx-store/db.js +31 -0
- package/packages/mailx-store/db.js.map +1 -1
- package/packages/mailx-store/db.ts +25 -0
|
@@ -442,6 +442,20 @@ export class MailxDB {
|
|
|
442
442
|
}
|
|
443
443
|
this.db.exec("PRAGMA journal_mode = WAL");
|
|
444
444
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
445
|
+
// WAL hygiene. With THREE connections (main writer, sync-worker writer,
|
|
446
|
+
// read-worker reader) the WAL was never getting checkpointed — failed
|
|
447
|
+
// writes (two-writer contention) never commit, so the auto-checkpoint
|
|
448
|
+
// that normally fires on commit never ran, and the WAL ballooned to
|
|
449
|
+
// 71 MB (Bob 2026-06-14: every read/write crawled, `database is locked`
|
|
450
|
+
// everywhere, a bulk move took 51s and timed out). A bloated WAL is
|
|
451
|
+
// self-reinforcing: bigger WAL → slower writes → more lock failures →
|
|
452
|
+
// fewer commits → no checkpoint. Boot is the one moment main is the
|
|
453
|
+
// SOLE connection (read/sync workers spawn later), so TRUNCATE here
|
|
454
|
+
// resets the file to empty; `checkpoint()` on a timer keeps it small.
|
|
455
|
+
try {
|
|
456
|
+
const r = this.db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get() as any;
|
|
457
|
+
console.log(` [db] boot WAL checkpoint: busy=${r?.busy} log=${r?.log} checkpointed=${r?.checkpointed}`);
|
|
458
|
+
} catch (e: any) { console.error(` [db] boot WAL checkpoint failed: ${e?.message || e}`); }
|
|
445
459
|
// Multi-writer foundation for the sync-worker migration: once sync runs
|
|
446
460
|
// on its own thread with its own write connection, it and the main
|
|
447
461
|
// thread are two writers on one WAL file. WAL serializes writers, so a
|
|
@@ -2644,6 +2658,17 @@ export class MailxDB {
|
|
|
2644
2658
|
* already open this just runs `fn` (its writes join the open txn);
|
|
2645
2659
|
* otherwise it owns a fresh BEGIN/COMMIT. `fn` MUST be synchronous so it
|
|
2646
2660
|
* can't span an await and leave a transaction open across a yield. */
|
|
2661
|
+
/** Run a WAL checkpoint to bound the WAL file size. PASSIVE never blocks
|
|
2662
|
+
* on readers — it reclaims frames older than the oldest live snapshot and
|
|
2663
|
+
* returns immediately otherwise. Drive it from ONE connection (main) on a
|
|
2664
|
+
* timer so the WAL can't balloon while three connections share the file.
|
|
2665
|
+
* Returns {busy, log, checkpointed} (log = frames in WAL, checkpointed =
|
|
2666
|
+
* frames moved into the db) or null on error. */
|
|
2667
|
+
checkpoint(mode: "PASSIVE" | "FULL" | "RESTART" | "TRUNCATE" = "PASSIVE"): { busy: number; log: number; checkpointed: number } | null {
|
|
2668
|
+
try { return this.db.prepare(`PRAGMA wal_checkpoint(${mode})`).get() as any; }
|
|
2669
|
+
catch { return null; }
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2647
2672
|
runInTxn<T>(fn: () => T): T {
|
|
2648
2673
|
if (this.db.isTransaction) return fn();
|
|
2649
2674
|
this.db.exec("BEGIN");
|