Fix error handling when DB.init() fails

The `DB.init()` can fail temporarily for a variety of reasons such
as the database being locked. Previously, the DB would save the
`*sql.DB` connection even if a step failed and this prevented the
database from attempting initialization again. This change makes it
so that the connection is only saved if initialization is successful.
On failure, the initialization process will be retried on next sync.
This commit is contained in:
Ben Johnson
2021-02-24 15:43:28 -07:00
parent d6ece0b826
commit d802e15b4f

21
db.go
View File

@@ -381,11 +381,28 @@ func (db *DB) init() (err error) {
dsn := db.path dsn := db.path
dsn += fmt.Sprintf("?_busy_timeout=%d", BusyTimeout.Milliseconds()) dsn += fmt.Sprintf("?_busy_timeout=%d", BusyTimeout.Milliseconds())
// Connect to SQLite database & enable WAL. // Connect to SQLite database.
if db.db, err = sql.Open("sqlite3", dsn); err != nil { if db.db, err = sql.Open("sqlite3", dsn); err != nil {
return err return err
} else if _, err := db.db.Exec(`PRAGMA journal_mode = wal;`); err != nil { }
// Ensure database is closed if init fails.
// Initialization can retry on next sync.
defer func() {
if err != nil {
db.releaseReadLock()
db.db.Close()
db.db = nil
}
}()
// Enable WAL and ensure it is set. New mode should be returned on success:
// https://www.sqlite.org/pragma.html#pragma_journal_mode
var mode string
if err := db.db.QueryRow(`PRAGMA journal_mode = wal;`).Scan(&mode); err != nil {
return fmt.Errorf("enable wal: %w", err) return fmt.Errorf("enable wal: %w", err)
} else if mode != "wal" {
return fmt.Errorf("enable wal failed, mode=%q", mode)
} }
// Disable autocheckpoint for litestream's connection. // Disable autocheckpoint for litestream's connection.