From 3297244d5d08d355b26c5b3624675877ad49bb22 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Wed, 24 Jul 2019 12:16:43 +0200 Subject: [PATCH] db: retry on sqlite locked error Since we are using the shared cache with the lock notify we won't receive SQLITE_BUSY errors but we could receive SQLITE_LOCKED errors due to deadlocks or locked tables on concurrent read and write transactions. This patch catches this kind of errors and retries the tx until maxTxRetries. --- internal/db/db.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/db/db.go b/internal/db/db.go index 79bb8cb..d3402dc 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -20,7 +20,7 @@ import ( "regexp" "time" - _ "github.com/mattn/go-sqlite3" + "github.com/mattn/go-sqlite3" errors "golang.org/x/xerrors" ) @@ -29,6 +29,8 @@ type Type string const ( Sqlite3 Type = "sqlite3" Postgres Type = "postgres" + + maxTxRetries = 20 ) type dbData struct { @@ -171,6 +173,25 @@ func (db *DB) NewTx() (*Tx, error) { } func (db *DB) Do(f func(tx *Tx) error) error { + retries := 0 + for { + err := db.do(f) + if err != nil { + var sqerr sqlite3.Error + if errors.As(err, &sqerr) { + if sqerr.Code == sqlite3.ErrLocked { + retries++ + if retries <= maxTxRetries { + continue + } + } + } + } + return err + } +} + +func (db *DB) do(f func(tx *Tx) error) error { tx, err := db.NewTx() if err != nil { return err