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.