Advisory Locks

Warning

postgresql.alock is a new feature in v1.0.

Explicit Locking in PostgreSQL.

PostgreSQL’s advisory locks offer a cooperative synchronization primitive. These are used in cases where an application needs access to a resource, but using table locks may cause interference with other operations that can be safely performed alongside the application-level, exclusive operation.

Advisory locks can be used by directly executing the stored procedures in the database or by using the postgresql.alock.ALock subclasses, which provides a context manager that uses those stored procedures.

Currently, only two subclasses exist. Each represents the lock mode supported by PostgreSQL’s advisory locks:

  • postgresql.alock.ShareLock
  • postgresql.alock.ExclusiveLock

Acquiring ALocks

An ALock instance represents a sequence of advisory locks. A single ALock can acquire and release multiple advisory locks by creating the instance with multiple lock identifiers:

>>> from postgresql import alock
>>> table1_oid = 192842
>>> table2_oid = 192849
>>> l = alock.ExclusiveLock(db, (table1_oid, 0), (table2_oid, 0))
>>> l.acquire()
>>> ...
>>> l.release()

postgresql.alock.ALock is similar to threading.RLock; in order for an ALock to be released, it must be released the number of times it has been acquired. ALocks are associated with and survived by their session. Much like how RLocks are associated with the thread they are acquired in: acquiring an ALock again will merely increment its count.

PostgreSQL allows advisory locks to be identified using a pair of int4 or a single int8. ALock instances represent a sequence of those identifiers:

>>> from postgresql import alock
>>> ids = [(0,0), 0, 1]
>>> with alock.ShareLock(db, *ids):
...  ...

Both types of identifiers may be used within the same ALock, and, regardless of their type, will be aquired in the order that they were given to the class’ constructor. In the above example, (0,0) is acquired first, then 0, and lastly 1.

ALocks

postgresql.alock.ALock is abstract; it defines the interface and some common functionality. The lock mode is selected by choosing the appropriate subclass.

There are two:

postgresql.alock.ExclusiveLock(database, *identifiers)
Instantiate an ALock object representing the identifiers for use with the database. Exclusive locks will conflict with other exclusive locks and share locks.
postgresql.alock.ShareLock(database, *identifiers)
Instantiate an ALock object representing the identifiers for use with the database. Share locks can be acquired when a share lock with the same identifier has been acquired by another backend. However, an exclusive lock with the same identifier will conflict.

ALock Interface Points

Methods and properties available on postgresql.alock.ALock instances:

alock.acquire(blocking = True)

Acquire the advisory locks represented by the alock object. If blocking is True, the default, the method will block until locks on all the identifiers have been acquired.

If blocking is False, acquisition may not block, and success will be indicated by the returned object: True if all lock identifiers were acquired and False if any of the lock identifiers could not be acquired.

alock.release()
Release the advisory locks represented by the alock object. If the lock has not been acquired, a RuntimeError will be raised.
alock.locked()
Returns a boolean describing whether the locks are held or not. This will return False if the lock connection has been closed.
alock.__enter__()
Alias to acquire; context manager protocol. Always blocking.
alock.__exit__(typ, val, tb)
Alias to release; context manager protocol.

Table Of Contents

Previous topic

Notification Management

Next topic

Cluster Management

This Page