89 lines
3.6 KiB
Markdown
89 lines
3.6 KiB
Markdown
# Wal-Mode Blocking Locks
|
|
|
|
On some Unix-like systems, SQLite may be configured to use POSIX blocking locks
|
|
by:
|
|
|
|
* building the library with SQLITE\_ENABLE\_SETLK\_TIMEOUT defined, and
|
|
* configuring a timeout in ms using the sqlite3\_busy\_timeout() API.
|
|
|
|
Blocking locks may be advantageous as (a) waiting database clients do not
|
|
need to continuously poll the database lock, and (b) using blocking locks
|
|
facilitates transfer of OS priority between processes when a high priority
|
|
process is blocked by a lower priority one.
|
|
|
|
Only read/write clients use blocking locks. Clients that have read-only access
|
|
to the \*-shm file nevery use blocking locks.
|
|
|
|
Threads or processes that access a single database at a time never deadlock as
|
|
a result of blocking database locks. But it is of course possible for threads
|
|
that lock multiple databases simultaneously to do so. In most cases the OS will
|
|
detect the deadlock and return an error.
|
|
|
|
## Wal Recovery
|
|
|
|
Wal database "recovery" is a process required when the number of connected
|
|
database clients changes from zero to one. In this case, a client is
|
|
considered to connect to the database when it first reads data from it.
|
|
Before recovery commences, an exclusive WRITER lock is taken.
|
|
|
|
Without blocking locks, if two clients attempt recovery simultaneously, one
|
|
fails to obtain the WRITER lock and either invokes the busy-handler callback or
|
|
returns SQLITE\_BUSY to the user. With blocking locks configured, the second
|
|
client blocks on the WRITER lock.
|
|
|
|
## Database Readers
|
|
|
|
Usually, read-only are not blocked by any other database clients, so they
|
|
have no need of blocking locks.
|
|
|
|
If a read-only transaction is being opened on a snapshot, the CHECKPOINTER
|
|
lock is required briefly as part of opening the transaction (to check that a
|
|
checkpointer is not currently overwriting the snapshot being opened). A
|
|
blocking lock is used to obtain the CHECKPOINTER lock in this case. A snapshot
|
|
opener may therefore block on and transfer priority to a checkpointer in some
|
|
cases.
|
|
|
|
## Database Writers
|
|
|
|
A database writer must obtain the exclusive WRITER lock. It uses a blocking
|
|
lock to do so if any of the following are true:
|
|
|
|
* the transaction is an implicit one consisting of a single DML or DDL
|
|
statement, or
|
|
* the transaction is opened using BEGIN IMMEDIATE or BEGIN EXCLUSIVE, or
|
|
* the first SQL statement executed following the BEGIN command is a DML or
|
|
DDL statement (not a read-only statement like a SELECT).
|
|
|
|
In other words, in all cases except when an open read-transaction is upgraded
|
|
to a write-transaction. In that case a non-blocking lock is used.
|
|
|
|
## Database Checkpointers
|
|
|
|
Database checkpointers takes the following locks, in order:
|
|
|
|
* The exclusive CHECKPOINTER lock.
|
|
* The exclusive WRITER lock (FULL, RESTART and TRUNCATE only).
|
|
* Exclusive lock on read-mark slots 1-N. These are immediately released after being taken.
|
|
* Exclusive lock on read-mark 0.
|
|
* Exclusive lock on read-mark slots 1-N again. These are immediately released
|
|
after being taken (RESTART and TRUNCATE only).
|
|
|
|
All of the above use blocking locks.
|
|
|
|
## Summary
|
|
|
|
With blocking locks configured, the only cases in which clients should see an
|
|
SQLITE\_BUSY error are:
|
|
|
|
* if the OS does not grant a blocking lock before the configured timeout
|
|
expires, and
|
|
* when an open read-transaction is upgraded to a write-transaction.
|
|
|
|
In all other cases the blocking locks implementation should prevent clients
|
|
from having to handle SQLITE\_BUSY errors and facilitate appropriate transfer
|
|
of priorities between competing clients.
|
|
|
|
Clients that lock multiple databases simultaneously must be wary of deadlock.
|
|
|
|
|