Post by Simon SlavinYes. SQLite incorporates multi-process/multi-thread locking, exponential backoff, and such things. This all works fine unless you have intentionally turned off those features.
I did find that SQLite’s own locking was less effective/fair than using a mutex, and in situations with a lot of write contention could lead to starvation and timeouts. It’s possible I was doing things wrong, as the wrapper library I started with included a SQLite busy-handler that would wait-and-retry. (But IIRC, if I removed the busy handler altogether, SQLite would just immediately return a db-busy error if another thread had a lock.)
There were situations where one thread was rapidly writing to the database, in multiple transactions but with only brief gaps between them, and other connections on other threads that wanted to make small writes were starved.
Apparently the waiting connections were trying to spin-lock, i.e. attempting to get the write lock, and on failure sleeping a little while and retrying. But if the first thread has the write lock 99% of the time, it can take quite a while for another thread to get lucky and snatch the lock. If there are multiple other threads wanting the lock, it takes multiple times as long.
To fix this I added my own (pthread) mutex and used it as a bottleneck between my code and SQLite, so before trying any writes a thread would wait to lock the mutex. The advantage is that the mutex keeps a queue of waiting threads, so it grants access fairly, to the thread that’s been waiting the longest. But this gets harder to implement, of course, if the database is being used in multiple *processes*, not just threads in a single process.
—Jens