From d802e15b4f913ef8a85b77c8e844c8561d7392ca Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Wed, 24 Feb 2021 15:43:28 -0700 Subject: [PATCH] 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. --- db.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/db.go b/db.go index fafdb62..7e6d36b 100644 --- a/db.go +++ b/db.go @@ -381,11 +381,28 @@ func (db *DB) init() (err error) { dsn := db.path 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 { 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) + } else if mode != "wal" { + return fmt.Errorf("enable wal failed, mode=%q", mode) } // Disable autocheckpoint for litestream's connection.