doc database: retry on SQLITE_READONLY_ROLLBACK
The SQLITE_READONLY_ROLLBACK error is supposed to mean that a crash occurred and a hot journal exists that needs to be replayed (but can't, because the current connection is read-only). In practice, it seems that the error can happen even if there has been no crash. In that case, retrying in the same was as other transient errors allows the process to continue. A possible reason for the spurious error: In the implementation of SQLite, comments in hasHotJournal() mention the possibility of false positives (ticket #3883) and how the false positive will be handled in the playback mechanism after obtaining an exclusive lock. The check for a read-only connection after hasHotJournal() is called, however, happens before that lock is acquired. So, it seems like the race condition could trigger a false SQLITE_READONLY_ROLLBACK error.
This commit is contained in:
parent
707f888c83
commit
e0506038ba
|
@ -453,7 +453,8 @@
|
|||
(define (simplify-status s)
|
||||
(cond
|
||||
[(or (= SQLITE_IOERR_BLOCKED s)
|
||||
(= SQLITE_IOERR_LOCK s))
|
||||
(= SQLITE_IOERR_LOCK s)
|
||||
(= SQLITE_READONLY_ROLLBACK s))
|
||||
;; Kept in extended form, because these indicate
|
||||
;; cases where retry is appropriate
|
||||
s]
|
||||
|
@ -468,6 +469,7 @@
|
|||
[,SQLITE_LOCKED locked "table in the database is locked"]
|
||||
[,SQLITE_NOMEM nomem "malloc() failed"]
|
||||
[,SQLITE_READONLY readonly "attempt to write a readonly database"]
|
||||
[,SQLITE_READONLY_ROLLBACK readonly-rollback "attempt to write a readonly database (hot journal)"]
|
||||
[,SQLITE_INTERRUPT interrupt "operation terminated by sqlite3_interrupt()"]
|
||||
[,SQLITE_IOERR ioerr "some kind of disk I/O error occurred"]
|
||||
[,SQLITE_IOERR_BLOCKED ioerr-blocked "some kind of disk I/O error occurred (blocked)"]
|
||||
|
@ -495,7 +497,7 @@
|
|||
SQLITE_IOERR_BLOCKED SQLITE_IOERR_LOCK))
|
||||
|
||||
(define include-db-file-status-list
|
||||
(list SQLITE_READONLY SQLITE_PERM SQLITE_ABORT SQLITE_BUSY SQLITE_LOCKED
|
||||
(list SQLITE_READONLY SQLITE_READONLY_ROLLBACK SQLITE_PERM SQLITE_ABORT SQLITE_BUSY SQLITE_LOCKED
|
||||
SQLITE_IOERR SQLITE_IOERR_BLOCKED SQLITE_IOERR_LOCK SQLITE_CORRUPT
|
||||
SQLITE_NOTFOUND SQLITE_FULL SQLITE_CANTOPEN SQLITE_PROTOCOL SQLITE_EMPTY
|
||||
SQLITE_FORMAT SQLITE_NOTADB))
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
;; Extended error codes:
|
||||
(define SQLITE_IOERR_BLOCKED (bitwise-ior SQLITE_IOERR (arithmetic-shift 11 8)))
|
||||
(define SQLITE_IOERR_LOCK (bitwise-ior SQLITE_IOERR (arithmetic-shift 15 8)))
|
||||
(define SQLITE_READONLY_ROLLBACK (bitwise-ior SQLITE_READONLY (arithmetic-shift 3 8)))
|
||||
|
||||
(define SQLITE_INTEGER 1)
|
||||
(define SQLITE_FLOAT 2)
|
||||
|
|
|
@ -487,7 +487,12 @@
|
|||
(let ([s (exn:fail:sql-sqlstate v)])
|
||||
(or (eq? s 'busy)
|
||||
(eq? s 'ioerr-blocked)
|
||||
(eq? s 'ioerr-lock)))))
|
||||
(eq? s 'ioerr-lock)
|
||||
;; The `SQLITE_READONLY_ROLLBACK` result is supposed
|
||||
;; to mean that a hot journal exists due to a crash,
|
||||
;; but it seems to happen even without crashes, so
|
||||
;; treat it is a reason to retry:
|
||||
(eq? s 'readonly-rollback)))))
|
||||
|
||||
(define (call-with-lock-handler handler thunk)
|
||||
(with-handlers* ([exn:fail:retry?
|
||||
|
|
Loading…
Reference in New Issue
Block a user