Closed frasertweedale closed 2 years ago
@romanofski please try out this branch and let me know your feedback, particular around performance.
Gave it a whirl and can't notice much of a difference. I'll fix up the nix errors after merging. Nice work @frasertweedale !!!
@romanofski thanks for testing. I'll wait til #477 is merged, then rebase and "mark ready" this PR.
@romanofski good for review and merge.
We have had several bugs due to concurrency issues when dealing with the notmuch database. It was long proposed to [attempt to] avoid these issues by forcing all database interaction to be performed by a single, dedicated server thread. This commit implements that proposal.
The implementation is across two modules:
Purebred.Storage.Server
: the server core. Intended for use byPurebred.Storage.Client
and not intended for direct use by other parts of Purebred.Purebred.Storage.Client
: implements the API for use by the rest of Purebred. Mimics the API ofPurebred.Storage.Notmuch
(now removed) although the types have changed a little.The server thread responds to commands received via an STM TQueue. The
Command
type has three constructors:Command: encapsulate a IO computation that takes the database handle as an argument. The result of the computation will be written to the
TMVar
(if given)Open: an explicit "open database" command. This is used internally by Purebred.Storage.Server and not exported.
Close: an explicit "close database" command. This is used internally by Purebred.Storage.Server and not exported. It also doesn't really close the database, but rather causes the server to release the database handle. The actual close will be performed by the finalizer when the handle gets GC'd.
Purebred spawns the server thread at application start, and immediately sends an Open command. If that command fails, Purebred terminates (because it indicates a misconfiguration or other critical problem).
To avoid holding a write lock on the notmuch database indefinitely, we close the database after 2 seconds of inactivity. The server will re-open the database upon receiving the next Command. We use the stm-delay library to implement the timeout behaviour.
The server is stored in the
AppState
and the functions fromPurebred.Storage.Client
take the server as an argument.