Documentation
¶
Overview ¶
Package filegate queues the writers in one process that share a database file, first come first served, with lease statements ahead of the rest.
SQLite lets one writer at a time hold a file's write lock, and a writer that finds it taken waits in SQLite's busy handler: a sleep, then another try, with no queue. A writer that just released the lock tries again at once and usually wins it back from the writers asleep in the handler, so under a burst of writers a single unlucky one can wait for everyone else's whole run, which a long busy_timeout only postpones failing on. A gate in front of the write makes the writers in one process take turns, so the number of writers that contend for the file is the number of processes, and a slow disk (where each write is long) cannot starve one of them.
A lease renewal has a deadline (a fraction of the lease's TTL) that an ordinary write does not, so EnterFirst puts it ahead of every waiting ordinary writer; it waits only for the writer already inside.
Handles are matched by the identity of the file (device and inode, or volume and file index), so every spelling of a path (a relative path, a symlink, a different case on a case-insensitive file system) shares one gate. A gate does not order writers in different processes: they still contend through SQLite.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Gate ¶
type Gate struct {
// contains filtered or unexported fields
}
A Gate is a handle on the queue of one database file.
func For ¶
For returns the gate of the database file at path, shared by every handle in the process that opens the same file. A file that does not exist yet is created empty first (SQLite takes an empty file for a new database), so that it has an identity; if it cannot be, the gate is keyed by the cleaned absolute path. An in-memory database (":memory:" or a "mode=memory" URI) is never shared between handles, so its gate admits writers without queueing. Release the handle with Close.
func (*Gate) Close ¶
func (h *Gate) Close()
Close drops the handle; the gate is forgotten once every handle on it is closed. Closing a handle twice is the same as once. A closed handle still admits writers.
func (*Gate) Enter ¶
Enter waits for this handle's turn to write and returns the function that ends it, which the caller must call exactly once. It returns ctx's error if ctx ends first, without taking a turn.
func (*Gate) EnterFirst ¶
EnterFirst is Enter for a statement with a deadline: it is admitted ahead of every writer waiting in Enter, behind only the writer inside and the EnterFirst callers that asked before it.