8.3. Buffer Manager Locks

Because multiple backend processes can access the same pages in the Buffer Manager, mechanisms are required to coordinate their access. PostgreSQL’s Buffer Manager uses two types of lightweight locks for this purpose:

  • BufMappingLock: The buffer mapping hash table virtually is divided into multiple partitions (128 by default), each protected by a separate lock.
  • content_lock: Each buffer has a corresponding lock in its buffer descriptor to protect access to the page contents.

Historically, buffer descriptors also contained a spinlock, which protected updates to internal fields. In PostgreSQL 9.6, these updates were changed to use atomic operations, making the spinlock unnecessary. The Buffer Manager therefore no longer uses the spinlock and uses the two lightweight locks described above.

This section describes these locks in the following subsections.

Note

The locks described in this section are part of a synchronization mechanism for the buffer manager. They do not relate to SQL statements or SQL options.

8.3.1. Buffer Table Locks

The BufMappingLock protects the buffer mapping hash table from concurrent access by multiple backend processes.

A backend process acquires a shared BufMappingLock to search for an entry in the hash table, and acquires an exclusive lock to insert or delete an entry.

To reduce contention, the BufMappingLock is divided into multiple partitions (128 by default). Each partition protects a specific set of hash table buckets.

Figure 8.8 shows the effect of splitting BufMappingLock. Two backend processes can simultaneously hold different BufMappingLock partitions in exclusive mode to insert new data entries. If BufMappingLock were a single system-wide lock, one process would have to wait for the other to finish.

Figure 8.8. Two processes simultaneously acquire the respective partitions of BufMappingLock in exclusive mode to insert new data entries.
Historical Information

The BufMappingLock was introduced in version 8.1 (2005). Until version 9.4 (2014), the BufMappingLock was split into 16 partitions by default.

Before the introduction of BufMappingLock, PostgreSQL used BufMgrLock. This giant lock mechanism had to be acquired whenever the shared buffer was accessed, which resulted in poor concurrency.

8.3.2. content_lock

Each buffer descriptor uses a lightweight lock, content_lock, to control access to the page stored in the buffer pool slot.

The content_lock is a typical lock that enforces access restrictions. It can be used in shared and exclusive modes.

A backend process acquires a shared content_lock of the buffer descriptor when reading a page.

An exclusive content_lock is acquired when performing the following tasks:

  • Inserting rows (tuples) into the stored page or changing the t_xmin/t_xmax fields of tuples within the page.
  • Physically removing tuples or compacting free space on the stored page.
  • Freezing tuples within the stored page.

The official README file provides more details.