5.5. Transaction Snapshot

A transaction snapshot records information about multiple transaction IDs visible to a transaction at a specific point in time. It contains information about active transactions — specifically, those that are currently in progress or have not yet started.

The following subsections first describe the information contained in a transaction snapshot and its textual representation, and then explain when snapshots are created and how they are used for tuple visibility checks.

5.5.1. Snapshot Information and Representation

A transaction snapshot is an internal data structure. PostgreSQL provides a human-readable textual representation of a snapshot in the format xmin:xmax:xip_list.

Each component is defined as follows:

  • xmin: The earliest txid that is still active. All earlier transactions are either committed and visible, or rolled back and dead.
  • xmax: The first as-yet-unassigned txid. All txids greater than or equal to this value have not started at the time of the snapshot and are therefore invisible.
  • xip_list: A list of active txids at the time of the snapshot. This list includes only active txids between xmin and xmax.

For example, 100:100: indicates that txids less than 100 are not active, while txids greater than or equal to 100 are active.

The function pg_current_snapshot returns a snapshot of the current transaction. For example:

testdb=# SELECT pg_current_snapshot();
 pg_current_snapshot
---------------------
 100:104:100,102
(1 row)

In the snapshot 100:104:100,102, xmin is 100, xmax is 104, and the xip_list contains 100 and 102.

Figure 5.8 illustrates two examples of snapshot representations.

Figure 5.8. Examples of transaction snapshot representation.
  • Example 1: ‘100:100:’ As shown in Figure 5.8(a), this snapshot indicates the following:

    • Txids less than 100 are not active (xmin = 100).
    • Txids greater than or equal to 100 are active (xmax = 100).
  • Example 2: ‘100:104:100,102’ As shown in Figure 5.8(b), this snapshot indicates the following:

    • Txids less than 100 are not active.
    • Txids greater than or equal to 104 are active.
    • Txids 100 and 102 are active because they appear in the xip_list.
    • Txids 101 and 103 are not active.

5.5.2. Snapshot Acquisition and Tuple Visibility

When a backend process requests a transaction snapshot, the transaction manager provides one that records the state of transactions at that point in time.

The timing of snapshot acquisition depends on the transaction’s isolation level:

  • Under the READ COMMITTED isolation level, a transaction obtains a new snapshot whenever an SQL command is executed.
  • In contrast, under the REPEATABLE READ or SERIALIZABLE isolation level, a transaction obtains a snapshot only when its first SQL command is executed.

These snapshots are essential for the visibility check of tuples, which is described in Section 5.7.

When performing a visibility check, transactions identified as active in the snapshot must be treated as in progress, even if they have since been committed or aborted. This rule creates the fundamental behavioral difference between READ COMMITTED and REPEATABLE READ (or SERIALIZABLE).

The following scenario, illustrated in Figure 5.9, demonstrates the interaction between the transaction manager and individual transactions.

Figure 5.9. Transaction manager and transactions.

The transaction manager maintains information on all currently running transactions. In this scenario, three transactions start sequentially: Transaction_A and Transaction_B use READ COMMITTED, while Transaction_C uses REPEATABLE READ.

  • T1:
    Transaction_A starts and executes its first SELECT command. At this moment, the transaction manager assigns txid 200 and returns the snapshot ‘200:200:’.

  • T2:
    Transaction_B starts and executes its first SELECT command. The transaction manager assigns txid 201 and returns the snapshot ‘200:200:’ because Transaction_A (txid 200) is still in progress. Consequently, Transaction_A is invisible to Transaction_B.

  • T3:
    Transaction_C starts and executes its first SELECT command. The transaction manager assigns txid 202 and returns the snapshot ‘200:200:’. Both Transaction_A and Transaction_B are invisible to Transaction_C.

  • T4:
    Transaction_A commits. The transaction manager removes the information for this transaction.

  • T5:
    Transaction_B and Transaction_C execute subsequent SELECT commands:

    • Transaction_B obtains a new snapshot because it operates at the READ COMMITTED level. It receives snapshot ‘201:201:’ because Transaction_A is now committed. Thus, Transaction_A becomes visible to Transaction_B.
    • In contrast, Transaction_C does not request a new snapshot. It continues to use the initial snapshot (‘200:200:’) as required by the REPEATABLE READ level. Therefore, Transaction_A remains invisible to Transaction_C.