Do I need to worry about deadlocks when using a Freeze background-save evictor?

When you read and write a database concurrently, deadlocks are pretty much unavoidable. With a Freeze background-save evictor, there are two groups of threads accessing the underlying database:

  • The threads dispatching the requests to your servants. These threads read data from the underlying Berkeley DB database to recreate servants when needed. During each read, Berkeley DB acquires read-locks on one or more pages of the underlying file.
  • The "saving thread", a thread managed by Freeze and responsible for saving updates periodically. Each save corresponds to a Berkeley DB transaction during which Berkeley DB acquires write-locks on pages of the underlying file.

Sometimes the read locks and write locks are acquired in conflicting order. Fortunately, instead of bringing everything to a stand-still (a real deadlock), Berkeley DB detects the problem and "kills" one of the participants to avoid the deadlock. While "kill" is the standard term in this context, it does not mean a thread gets forcibly terminated: it's just a Berkeley DB call that raises a deadlock exception to tell the thread "you were about to create a deadlock, please try again".

Every operation on a Freeze background-save evictor that acquires locks also releases them. In particular when you create and use a Freeze Evictor iterator, the implementation creates a Berkeley DB cursor to retrieve each batch of objects and never keeps a cursor alive across calls. Furthermore, the Freeze Evictor implementation traps deadlock exceptions and immediately retries the database operation. As a result, no deadlock exception ever bubbles through any Freeze Evictor operation, and you don't need to worry about retrying-on-deadlock when you use a Freeze background-save evictor.

This does not mean you can ignore deadlocks altogether. You can see deadlocks occurring (and operations being retried) in your Freeze background-save evictor by setting the property Freeze.Warn.Deadlocks to 1. An occasional deadlock is expected and nothing to worry about. However if deadlocks occur often, the performance of your application will suffer, and then you should try to reduce their frequency by reducing the size of each transaction in the saving thread (see Freeze.Evictor.env-name.filename.MaxTxSize) and/or by saving more often (see the properties Freeze.Evictor.env-name.filename.SavePeriod and Freeze.Evictor.env-name.filename.SaveSizeTrigger).

See Also