diff --git a/src/config.ts b/src/config.ts index cce1ce2..246bf5a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -144,9 +144,25 @@ const Conf = { local(path: string): string { return mergePaths(Conf.localDomain, path); }, + /** URL to send Sentry errors to. */ get sentryDsn() { return Deno.env.get('SENTRY_DSN'); }, + /** SQLite settings. */ + sqlite: { + /** + * Number of bytes to use for memory-mapped IO. + * https://www.sqlite.org/pragma.html#pragma_mmap_size + */ + get mmapSize(): number { + const value = Deno.env.get('SQLITE_MMAP_SIZE'); + if (value) { + return Number(value); + } else { + return 1024 * 1024 * 1024; + } + }, + }, }; const optionalBooleanSchema = z diff --git a/src/db.ts b/src/db.ts index 43d7f04..99339a8 100644 --- a/src/db.ts +++ b/src/db.ts @@ -3,6 +3,7 @@ import path from 'node:path'; import { DenoSqlite3, DenoSqliteDialect, FileMigrationProvider, Kysely, Migrator } from '@/deps.ts'; import { Conf } from '@/config.ts'; +import { getPragma, setPragma } from '@/pragma.ts'; interface DittoDB { events: EventRow; @@ -61,6 +62,19 @@ const db = new Kysely({ }), }); +// Set PRAGMA values. +await Promise.all([ + setPragma(db, 'synchronous', 'normal'), + setPragma(db, 'temp_store', 'memory'), + setPragma(db, 'mmap_size', Conf.sqlite.mmapSize), +]); + +// Log out PRAGMA values for debugging. +['journal_mode', 'synchronous', 'temp_store', 'mmap_size'].forEach(async (pragma) => { + const value = await getPragma(db, pragma); + console.log(`PRAGMA ${pragma} = ${value};`); +}); + const migrator = new Migrator({ db, provider: new FileMigrationProvider({ diff --git a/src/db/migrations/008_wal.ts b/src/db/migrations/008_wal.ts new file mode 100644 index 0000000..7f96226 --- /dev/null +++ b/src/db/migrations/008_wal.ts @@ -0,0 +1,9 @@ +import { Kysely, sql } from '@/deps.ts'; + +export async function up(db: Kysely): Promise { + await sql`PRAGMA journal_mode = WAL`.execute(db); +} + +export async function down(db: Kysely): Promise { + await sql`PRAGMA journal_mode = DELETE`.execute(db); +} diff --git a/src/pragma.ts b/src/pragma.ts new file mode 100644 index 0000000..f5aa8e4 --- /dev/null +++ b/src/pragma.ts @@ -0,0 +1,15 @@ +import { type Kysely, sql } from '@/deps.ts'; + +/** Set the PRAGMA and then read back its value to confirm. */ +function setPragma(db: Kysely, pragma: string, value: string | number) { + return sql.raw(`PRAGMA ${pragma} = ${value}`).execute(db); +} + +/** Get value of PRAGMA from the database. */ +async function getPragma(db: Kysely, pragma: string) { + const result = await sql.raw(`PRAGMA ${pragma}`).execute(db); + const row = result.rows[0] as Record | undefined; + return row?.[pragma]; +} + +export { getPragma, setPragma };