| 507 | } |
| 508 | |
| 509 | private async checkpointWal(mode: 'PASSIVE' | 'TRUNCATE'): Promise<{ busy: number; log: number; checkpointed: number } | null> { |
| 510 | if (!this.dbPath || this.dbPath === ':memory:') { |
| 511 | try { |
| 512 | const row = this.db.prepare(`PRAGMA wal_checkpoint(${mode})`).get() as Record<string, number> | undefined; |
| 513 | return row ? { busy: Number(row.busy), log: Number(row.log), checkpointed: Number(row.checkpointed) } : null; |
| 514 | } catch { |
| 515 | return null; |
| 516 | } |
| 517 | } |
| 518 | try { |
| 519 | const { Worker } = await import('node:worker_threads'); |
| 520 | const workerSource = ` |
| 521 | const { workerData, parentPort } = require('node:worker_threads'); |
| 522 | let row = null; |
| 523 | let err = null; |
| 524 | try { |
| 525 | const { DatabaseSync } = require('node:sqlite'); |
| 526 | const db = new DatabaseSync(workerData.dbPath); |
| 527 | const mode = workerData.mode === 'TRUNCATE' ? 'TRUNCATE' : 'PASSIVE'; |
| 528 | try { |
| 529 | if (mode === 'TRUNCATE') db.exec('PRAGMA busy_timeout = 2000'); |
| 530 | row = db.prepare('PRAGMA wal_checkpoint(' + mode + ')').get(); |
| 531 | } catch (e) { err = String(e && e.message || e); } |
| 532 | try { db.close(); } catch {} |
| 533 | } catch (e) { err = err || String(e && e.message || e); } |
| 534 | parentPort.postMessage({ row, err }); |
| 535 | `; |
| 536 | return await new Promise((resolve) => { |
| 537 | let settled = false; |
| 538 | const finish = (row?: Record<string, number> | null): void => { |
| 539 | if (settled) return; |
| 540 | settled = true; |
| 541 | resolve(row ? { busy: Number(row.busy), log: Number(row.log), checkpointed: Number(row.checkpointed) } : null); |
| 542 | }; |
| 543 | try { |
| 544 | const worker = new Worker(workerSource, { eval: true, workerData: { dbPath: this.dbPath, mode } }); |
| 545 | worker.once('message', (m: { row?: Record<string, number> | null; err?: string | null }) => { |
| 546 | if (m?.err && process.env.CODEGRAPH_WAL_VALVE_DEBUG) { |
| 547 | console.error(`[wal-valve] checkpoint worker (${mode}): ${m.err}`); |
| 548 | } |
| 549 | void worker.terminate(); |
| 550 | finish(m?.row ?? null); |
| 551 | }); |
| 552 | worker.once('error', () => { void worker.terminate(); finish(null); }); |
| 553 | worker.once('exit', () => finish(null)); |
| 554 | } catch { |
| 555 | finish(null); |
| 556 | } |
| 557 | }); |
| 558 | } catch { |
| 559 | return null; |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | /** |
| 564 | * Optimize database (vacuum and analyze) |