| 586 | } |
| 587 | |
| 588 | private async checkpointWal(mode: 'PASSIVE' | 'TRUNCATE'): Promise<{ busy: number; log: number; checkpointed: number } | null> { |
| 589 | if (!this.dbPath || this.dbPath === ':memory:') { |
| 590 | try { |
| 591 | const row = this.db.prepare(`PRAGMA wal_checkpoint(${mode})`).get() as Record<string, number> | undefined; |
| 592 | return row ? { busy: Number(row.busy), log: Number(row.log), checkpointed: Number(row.checkpointed) } : null; |
| 593 | } catch { |
| 594 | return null; |
| 595 | } |
| 596 | } |
| 597 | try { |
| 598 | const { Worker } = await import('node:worker_threads'); |
| 599 | const workerSource = ` |
| 600 | const { workerData, parentPort } = require('node:worker_threads'); |
| 601 | let row = null; |
| 602 | let err = null; |
| 603 | try { |
| 604 | const { DatabaseSync } = require('node:sqlite'); |
| 605 | const db = new DatabaseSync(workerData.dbPath); |
| 606 | const mode = workerData.mode === 'TRUNCATE' ? 'TRUNCATE' : 'PASSIVE'; |
| 607 | try { |
| 608 | if (mode === 'TRUNCATE') db.exec('PRAGMA busy_timeout = 2000'); |
| 609 | row = db.prepare('PRAGMA wal_checkpoint(' + mode + ')').get(); |
| 610 | } catch (e) { err = String(e && e.message || e); } |
| 611 | try { db.close(); } catch {} |
| 612 | } catch (e) { err = err || String(e && e.message || e); } |
| 613 | parentPort.postMessage({ row, err }); |
| 614 | `; |
| 615 | return await new Promise((resolve) => { |
| 616 | let settled = false; |
| 617 | const finish = (row?: Record<string, number> | null): void => { |
| 618 | if (settled) return; |
| 619 | settled = true; |
| 620 | resolve(row ? { busy: Number(row.busy), log: Number(row.log), checkpointed: Number(row.checkpointed) } : null); |
| 621 | }; |
| 622 | try { |
| 623 | const worker = new Worker(workerSource, { eval: true, workerData: { dbPath: this.dbPath, mode } }); |
| 624 | worker.once('message', (m: { row?: Record<string, number> | null; err?: string | null }) => { |
| 625 | if (m?.err && process.env.CODEGRAPH_WAL_VALVE_DEBUG) { |
| 626 | console.error(`[wal-valve] checkpoint worker (${mode}): ${m.err}`); |
| 627 | } |
| 628 | void worker.terminate(); |
| 629 | finish(m?.row ?? null); |
| 630 | }); |
| 631 | worker.once('error', () => { void worker.terminate(); finish(null); }); |
| 632 | worker.once('exit', () => finish(null)); |
| 633 | } catch { |
| 634 | finish(null); |
| 635 | } |
| 636 | }); |
| 637 | } catch { |
| 638 | return null; |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | /** |
| 643 | * Optimize database (vacuum and analyze) |