Ticket Hash: | df678d738adb24e9d7f5beff3a89928161c072fc | |||
Title: | Cache corruption following IO error on systems supporting atomic-write | |||
Status: | Closed | Type: | Code_Defect | |
Severity: | Critical | Priority: | Immediate | |
Subsystem: | Pager | Resolution: | Fixed | |
Last Modified: | 2012-12-18 14:04:30 | |||
Version Found In: | ||||
Description: | ||||
If SQLite is compiled with the SQLITE_ENABLE_ATOMIC_WRITE symbol defined and a custom VFS indicates that it is supported, SQLite writes transactions that modify a single database page on disk without creating a journal file. This is safe, since the system guarantees that single write required is atomic.
For such systems, SQLite creates an "in-memory journal" when a write transaction is opened. After the second database page is modified within the cache, a real journal file is created on disk and the contents of the in-memory journal file written to it. Processing then continues as per normal. Or, if the transaction never modifies a second page, the journal file is never created on disk. If the user opens a write transaction and then issues a ROLLBACK command after modifying a single page, the contents of the in-memory journal are used to restore the page-cache to its original state. However, due to a bug, if an IO or disk full error occurs while transferring the contents of the in-memory journal to disk, SQLite is not using the contents of the in-memory journal to restore the in-memory cache. Instead, it is attempting to use the contents of the file on disk (which was not written correctly - if at all). This means the single page that was modified in the cache is not being rolled back - cache corruption. For example, the INSERT statement in the SQL below writes to two database pages - one in the table b-tree and the other in the index. Internally, SQLite first modifies the table and stores the old page image in the in-memory journal. Before modifying the index, it attempts to write the contents of the in-memory journal out to disk. If it encounters a disk-full error while doing so, the subsequent rollback does not restore the contents of the table (due to the bug), leaving the connection with a corrupt cache. CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); INSERT INTO t1 VALUES(1, 2); |