Wait on a busy SQLite database and turn on WAL mode (closes #198)
check / check (push) Failing after 2s
check / check (push) Failing after 2s
Requests and the eviction pass write on separate connections, and with no busy timeout a write that met another one failed at once with "database is locked" and was lost. internal/database now adds _pragma=busy_timeout(5000) to every db_url, the default or one the operator sets, so such a write waits up to five seconds. The default db_url's _journal_mode=WAL is not a parameter the driver reads, so it is now _pragma=journal_mode(WAL). README.md and config.example.yml say what pixa adds to db_url. Model: opus-5-5
This commit was merged in pull request #200.
This commit is contained in:
@@ -320,7 +320,8 @@ func newFromSmartConfig(sc *smartconfig.Config) (*Config, error) {
|
||||
settingName(keyDBURL), errValueEmpty)
|
||||
}
|
||||
|
||||
c.DBURL = fmt.Sprintf("file:%s/state.sqlite3?_journal_mode=WAL", c.StateDir)
|
||||
// The driver sets the journal mode only through a _pragma parameter.
|
||||
c.DBURL = fmt.Sprintf("file:%s/state.sqlite3?_pragma=journal_mode(WAL)", c.StateDir)
|
||||
}
|
||||
|
||||
if loader.err != nil {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -9,6 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/smartconfig"
|
||||
|
||||
_ "modernc.org/sqlite" // SQLite driver registration
|
||||
)
|
||||
|
||||
// validTestSigningKey is a 32-character signing key that satisfies the
|
||||
@@ -94,12 +97,43 @@ func TestOmittedValuesUseDefaults(t *testing.T) {
|
||||
t.Errorf("AllowlistHosts = %v, want empty", c.AllowlistHosts)
|
||||
}
|
||||
|
||||
wantDBURL := "file:" + DefaultStateDir + "/state.sqlite3?_journal_mode=WAL"
|
||||
wantDBURL := "file:" + DefaultStateDir +
|
||||
"/state.sqlite3?_pragma=journal_mode(WAL)"
|
||||
if c.DBURL != wantDBURL {
|
||||
t.Errorf("DBURL = %q, want derived default %q", c.DBURL, wantDBURL)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDefaultDBURLOpensTheDatabaseInWALMode opens the db_url derived from
|
||||
// state_dir with the SQLite driver pixad uses and checks that the database
|
||||
// is in WAL mode: the driver ignores any parameter it does not know.
|
||||
func TestDefaultDBURLOpensTheDatabaseInWALMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c, err := configFromYAML(t, signingKeyLine+"state_dir: "+t.TempDir()+"\n")
|
||||
if err != nil {
|
||||
t.Fatalf("config with only state_dir set should be valid, got: %v", err)
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite", c.DBURL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open %q: %v", c.DBURL, err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() { _ = db.Close() })
|
||||
|
||||
var journalMode string
|
||||
|
||||
err = db.QueryRowContext(t.Context(), "PRAGMA journal_mode").Scan(&journalMode)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read the journal mode of %q: %v", c.DBURL, err)
|
||||
}
|
||||
|
||||
if journalMode != "wal" {
|
||||
t.Errorf("journal mode of %q = %q, want wal", c.DBURL, journalMode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExplicitValidValuesAreUsed(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user