Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/server/scripts/migrate-dev-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ const ensureNotInUse = Effect.fn("ensureDevDbNotInUse")(function* (databasePath:
const checkpoint = yield* Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;
yield* sql.unsafe("PRAGMA busy_timeout = 0").unprepared;
yield* sql.unsafe("PRAGMA checkpoint_fullfsync = ON").unprepared;
yield* sql.unsafe("BEGIN IMMEDIATE").unprepared;
yield* sql.unsafe("ROLLBACK").unprepared;
return yield* sql.unsafe<{ busy: number }>("PRAGMA wal_checkpoint(TRUNCATE)").unprepared;
Expand Down Expand Up @@ -483,6 +484,7 @@ export const runMigrateDevDb = Effect.fn("runMigrateDevDb")(function* (
// WAL does not survive VACUUM INTO; set it so first `vp run dev` finds
// the database exactly as server boot would have left it.
yield* sql.unsafe("PRAGMA journal_mode = WAL").unprepared;
yield* sql.unsafe("PRAGMA checkpoint_fullfsync = ON").unprepared;
}).pipe(
Effect.provide(NodeSqliteClient.layer({ filename: databasePath })),
wrapPhase("compact", databasePath),
Expand Down
20 changes: 20 additions & 0 deletions apps/server/scripts/t3-sqlite-state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ it.layer(NodeServices.layer)("t3-sqlite-state", (it) => {
if (result.operation === "query") {
assert.deepStrictEqual(result.rows, [{ id: 1, label: "existing" }]);
}

const checkpoint = yield* runSqliteState({
operation: "query",
baseDir,
sql: "PRAGMA checkpoint_fullfsync",
});
assert.equal(checkpoint.operation, "query");
if (checkpoint.operation === "query") {
assert.deepStrictEqual(checkpoint.rows, [{ checkpoint_fullfsync: 1 }]);
}

const fullfsync = yield* runSqliteState({
operation: "query",
baseDir,
sql: "PRAGMA fullfsync",
});
assert.equal(fullfsync.operation, "query");
if (fullfsync.operation === "query") {
assert.deepStrictEqual(fullfsync.rows, [{ fullfsync: 0 }]);
}
}),
);

Expand Down
2 changes: 2 additions & 0 deletions apps/server/scripts/t3-sqlite-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ export const runSqliteState = Effect.fn("runSqliteState")(function* (
const program = Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;
yield* sql.unsafe("PRAGMA busy_timeout = 5000").unprepared;
// This connection bypasses Sqlite.ts and can checkpoint state.sqlite.
yield* sql.unsafe("PRAGMA checkpoint_fullfsync = ON").unprepared;

if (input.operation === "query") {
const rows = yield* sql.unsafe<RawSqliteRow>(source).unprepared.pipe(
Expand Down
12 changes: 12 additions & 0 deletions apps/server/src/persistence/Layers/Sqlite.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,15 @@ it.effect("applies busy_timeout in the shared persistence setup", () =>
assert.equal(rows[0]?.timeout, 5000);
}).pipe(Effect.provide(SqlitePersistenceMemory)),
);

it.effect("uses F_FULLFSYNC for WAL checkpoints and leaves per-commit fullfsync off", () =>
Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;
const checkpoint = yield* sql<{
readonly checkpoint_fullfsync: number;
}>`PRAGMA checkpoint_fullfsync`;
const fullfsync = yield* sql<{ readonly fullfsync: number }>`PRAGMA fullfsync`;
assert.equal(checkpoint[0]?.checkpoint_fullfsync, 1);
assert.equal(fullfsync[0]?.fullfsync, 0);
}).pipe(Effect.provide(SqlitePersistenceMemory)),
);
3 changes: 3 additions & 0 deletions apps/server/src/persistence/Layers/Sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const setup = Layer.effectDiscard(
yield* sql`PRAGMA busy_timeout = 5000;`;
yield* sql`PRAGMA foreign_keys = ON;`;
yield* sql`PRAGMA journal_mode = WAL;`;
// Checkpoint syncs use F_FULLFSYNC where the platform provides it. Ordinary
// commit sync stays on fsync(); PRAGMA fullfsync is left off.
yield* sql`PRAGMA checkpoint_fullfsync = ON;`;
yield* runMigrations();
}),
);
Expand Down
Loading