Capturing SQLite Transactions
SQLite works by updating a subset of pages in the database file on every transaction. It does this by using the file system API and the exact steps depend on whether you’re using a rollback journal or a write-ahead log. LiteFS acts as a passthrough file system which intercepts these API calls and copies out the page sets for each transaction. These page sets are stored in an internal format called LTX that performs extensive consistency checking to ensure correctness. By applying these page sets in the LTX files in order, we can reconstruct the state of our SQLite database at any point in time. We can also copy them to another nodes in order to replicate the changes in real-time to our cluster.Rollback journal handling
The following steps occur when SQLite creates a transaction with either theDELETE, PERSIST, or TRUNCATE journal modes:
- Obtain an exclusive lock on the
RESERVEDbyte. - Create a journal file to start the transaction.
- Update page in the main database file while copying old pages to the journal.
- Invalidate the journal file to finish the transaction.
- Release the lock on the
RESERVEDbyte.
write(2) calls to the
database file. When the journal file is invalidated, LiteFS will copy out the
dirty pages in sequential order to an LTX transaction file.
Write-ahead log (WAL) handling
The following steps occur when SQLite creates a transaction with theWAL
journal mode:
- Acquire an exclusive lock on the
WAL_WRITE_LOCK. - Write a WAL frame to the end of the WAL for each new or updated page.
- On commit, write the new size of the database to the
commitfield in the last WAL frame header. - Release the exclusive lock on the
WAL_WRITE_LOCK.
Replication Position
Each database within the LiteFS directory contains a replication position. This position is a combination of the transaction ID (TXID) and the rolling checksum of the database contents. The TXID is an integer that is incremented with every write transaction that occurs. You can track the relative position between nodes by reading from the database’s position file in the LiteFS mount directory. For example, if you have a database called/mnt/db then you can read the position from /mnt/db-pos file: