Name Description Size
coop_transaction.rs This implements "cooperative transactions" for places. It relies on our decision to have exactly 1 general purpose "writer" connection and exactly one "sync writer" - ie, exactly 2 write connections. We'll describe the implementation and strategy, but note that most callers should use `PlacesDb::begin_transaction()`, which will do the right thing for your db type. The idea is that anything that uses the sync connection should use `chunked_coop_trransaction`. Code using this should regularly call `maybe_commit()`, and every second, will commit the transaction and start a new one. This means that in theory the other writable connection can start transactions and should block for a max of 1 second - well under the 5 seconds before that other writer will fail with a SQLITE_BUSY or similar error. However, in practice we see the writer thread being starved - even though it's waiting for a lock, the sync thread still manages to re-get the lock. In other words, the locks used by sqlite aren't "fair". So we mitigate this with a simple approach that works fine within our "exactly 2 writers" constraints: * Each database connection shares a mutex. * Before starting a transaction, each connection locks the mutex. * It then starts an "immediate" transaction - because sqlite now holds a lock on our behalf, we release the lock on the mutex. In other words, the lock is held only while obtaining the DB lock, then immediately released. The end result here is that if either connection is waiting for the database lock because the other already holds it, the waiting one is guaranteed to get the database lock next. One additional wrinkle here is that even if there was exactly one writer, there's still a possibility of SQLITE_BUSY if the database is being checkpointed. So we handle that case and perform exactly 1 retry. 9992
mod.rs 4415