mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-10-03 17:15:19 -07:00
perf(db): set the SQLite pragmas from a connect hook and clear WAL sidecars on db reset
This commit is contained in:
committed by
capy-ai-staging[bot]
parent
36bb6c1ad7
commit
ccc092bad0
+13
-23
@@ -1,10 +1,9 @@
|
|||||||
"""Engine creation, initialization, and session management."""
|
"""Engine creation, initialization, and session management."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sqlite3 as _sqlite3
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine, event
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
from .. import config
|
from .. import config
|
||||||
@@ -23,21 +22,6 @@ from .seed import backfill_generation_versions, seed_builtin_presets
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _make_connection(db_path: str) -> _sqlite3.Connection:
|
|
||||||
"""Open a SQLite connection with WAL journal mode and a 5-second busy timeout.
|
|
||||||
|
|
||||||
WAL allows concurrent readers while a write is in progress (the default
|
|
||||||
DELETE journal blocks all readers). This matters for voicebox because SSE
|
|
||||||
status polls and history queries run concurrently with the generation worker
|
|
||||||
writing to the same database. The busy timeout prevents "database is
|
|
||||||
locked" errors when two writers briefly contend on the same write slot.
|
|
||||||
"""
|
|
||||||
conn = _sqlite3.connect(db_path, check_same_thread=False)
|
|
||||||
conn.execute("PRAGMA journal_mode=WAL")
|
|
||||||
conn.execute("PRAGMA busy_timeout=5000")
|
|
||||||
return conn
|
|
||||||
|
|
||||||
|
|
||||||
# Initialized by init_db()
|
# Initialized by init_db()
|
||||||
engine = None
|
engine = None
|
||||||
SessionLocal = None
|
SessionLocal = None
|
||||||
@@ -54,15 +38,21 @@ def init_db() -> None:
|
|||||||
engine = create_engine(
|
engine = create_engine(
|
||||||
f"sqlite:///{_db_path}",
|
f"sqlite:///{_db_path}",
|
||||||
connect_args={"check_same_thread": False},
|
connect_args={"check_same_thread": False},
|
||||||
# Each connection enables WAL journal mode and sets a 5-second busy
|
)
|
||||||
# timeout. WAL allows concurrent readers during a write (the default
|
|
||||||
# DELETE/ROLLBACK journal blocks all readers), which matters for
|
@event.listens_for(engine, "connect")
|
||||||
# voicebox because SSE status polls and history queries run
|
def _set_sqlite_pragmas(dbapi_connection, _record) -> None:
|
||||||
|
# Each pooled connection enables WAL journal mode and sets a 5-second
|
||||||
|
# busy timeout. WAL allows concurrent readers during a write (the
|
||||||
|
# default DELETE/ROLLBACK journal blocks all readers), which matters
|
||||||
|
# for voicebox because SSE status polls and history queries run
|
||||||
# concurrently with the generation worker writing to the same db.
|
# concurrently with the generation worker writing to the same db.
|
||||||
# busy_timeout prevents "database is locked" errors when two
|
# busy_timeout prevents "database is locked" errors when two
|
||||||
# connections briefly contend on the same write slot.
|
# connections briefly contend on the same write slot.
|
||||||
creator=lambda: _make_connection(str(_db_path)),
|
cursor = dbapi_connection.cursor()
|
||||||
)
|
cursor.execute("PRAGMA journal_mode=WAL")
|
||||||
|
cursor.execute("PRAGMA busy_timeout=5000")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
|||||||
@@ -419,12 +419,14 @@ bun run tauri build
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# macOS
|
# macOS
|
||||||
rm ~/Library/Application\ Support/sh.voicebox.app/data/voicebox.db
|
rm ~/Library/Application\ Support/sh.voicebox.app/data/voicebox.db*
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
del %APPDATA%\sh.voicebox.app\data\voicebox.db
|
del %APPDATA%\sh.voicebox.app\data\voicebox.db*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The wildcard also removes the `voicebox.db-wal` and `voicebox.db-shm` sidecar files that SQLite keeps next to the database in WAL mode, so the reset starts completely clean.
|
||||||
|
|
||||||
Restart the app to create a fresh database.
|
Restart the app to create a fresh database.
|
||||||
|
|
||||||
## Model Issues
|
## Model Issues
|
||||||
|
|||||||
@@ -348,12 +348,12 @@ db-init: _ensure-venv
|
|||||||
# Reset database (delete + reinit)
|
# Reset database (delete + reinit)
|
||||||
[unix]
|
[unix]
|
||||||
db-reset:
|
db-reset:
|
||||||
rm -f {{ backend_dir }}/data/voicebox.db
|
rm -f {{ backend_dir }}/data/voicebox.db {{ backend_dir }}/data/voicebox.db-wal {{ backend_dir }}/data/voicebox.db-shm
|
||||||
just db-init
|
just db-init
|
||||||
|
|
||||||
[windows]
|
[windows]
|
||||||
db-reset:
|
db-reset:
|
||||||
if (Test-Path "{{ backend_dir }}/data/voicebox.db") { Remove-Item -Force "{{ backend_dir }}/data/voicebox.db" }
|
Remove-Item -Force -ErrorAction SilentlyContinue "{{ backend_dir }}/data/voicebox.db", "{{ backend_dir }}/data/voicebox.db-wal", "{{ backend_dir }}/data/voicebox.db-shm"
|
||||||
just db-init
|
just db-init
|
||||||
|
|
||||||
# ─── Utilities ────────────────────────────────────────────────────────
|
# ─── Utilities ────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user