Version 12.0.0
All Classes Functions Variables Typedefs Enumerations Enumerator Modules Pages
Snapshot
Data StructuresSource Location
WT_TXNsrc/include/txn.h

Caution: the Architecture Guide is not updated in lockstep with the code base and is not necessarily correct or complete for any specific release.

Transaction snapshots are an important mechanism for providing strong isolation guarantees in WiredTiger. WiredTiger will often maintain multiple versions of the users data throughout its lifetime, with which snapshots provide the mechanisms to ensure particular versions of that data are made accessible. Snapshots are importantly leveraged by WiredTiger to define the visibility rules for data such as isolating concurrent transactions from reading each others updates.

Transactions using Snapshots

Within the context of a WiredTiger transaction, a snapshot ensures specific versions of a record are accessible based on the time the snapshot was created. In particular, these accessibility rules are defined by a transactions isolation level. Transactions more specifically use snapshots for the following isolation levels:

  • snapshot: A snapshot is created at the beginning of a snapshot-level isolated transaction and is sustained throughout the entire life cycle of the transaction. In effect, a transaction using snapshot isolation will only read versions of records before the transaction started. The default isolation level is snapshot.
  • read-committed: Read-committed transactions ensure a transaction is able to see committed updates by other transactions at the time of reading. To achieve this, under a read-committed isolation, a snapshot is created when performing a search. The same snapshot is used for all subsequent reads until another search is called.
  • read-uncommitted: Read-uncommitted transactions do not take a snapshot, and allow dirty reads (uncommitted modifications made by other transactions).

See Transactional applications for further details about how WiredTiger transactions utilize snapshots to create isolation guarantees and implement concurrency control.

Snapshot Internals

Snapshots are implemented by capturing the global state of transactions in the system at the time of snapshot creation. Snapshots are managed within per-session transaction contexts, encapsulated by the WT_TXN data structure. The main data points that encapsulate a given snapshot include:

  • Maximum transaction ID: The maximum global transaction ID value seen when creating the snapshot. This being the upper bound value which all concurrent transactions IDs are currently smaller than. We resolve the maximum transaction ID value by reading the global current transaction ID/counter at the time of snapshot creation. Transactions with IDs greater than or equal to the maximum ID are considered invisible to the snapshot.
  • Concurrent transaction IDs: A list of transaction IDs that are concurrently active at the time of the snapshot creation. As these transactions are yet to be committed at the time of snapshot creation, transactions stored in this list are considered invisible when performing visibility checks. When building the list of concurrent transactions, WiredTiger walks a global array of running transactions, storing each walked transaction ID in a list managed by the snapshot. When walking the global set of running transactions, WiredTiger will ignore a transaction ID that is:
    1. Its own ID ie. the ID of the transaction creating the given snapshot. A transaction will always read its own updates.
    2. An ID that is greater than or equal to the snapshot's maximum transaction ID. As WiredTiger walks the global list, it may find a transaction that has concurrently allocated a new transaction ID, exceeding the snapshots maximum ID bounds. This will however be ignored as it is not considered visible at the time of snapshot creation.
  • Minimum transaction ID: The minimum global transaction ID value seen when creating the snapshot. This being the lower bound value which all concurrent transactions IDs are greater than or equal to. Transaction IDs strictly less than the minimum value are considered visible as these would've been allocated and committed before the snapshot was created. This value is usually taken to be the smallest transaction ID value found from the list of concurrent transactions.

An example of building out the aforementioned components of a snapshot can be seen in the below figure. This figure illustrates constructing a snapshot for a transaction with ID 8. Consider that at the given time, the concurrent running transactions are 3, 5, 7, 8 and the global current transaction ID is 9.

Snapshot Visibility

When determining if a transaction can read a given record, WiredTiger applies a visibility function to discern whether the committed value is visible. When using snapshot and read-committed isolated transactions, WiredTiger's visibility function will leverage a transactions snapshot information to determine if a given record is visible. When determining if a given transaction ID is visible to a snapshot, WiredTiger applies the below checks in the following order:

  1. The transaction ID is greater than or equal to the snapshots recorded maximum transaction ID: If satisfied, the transaction ID is invisible, as the ID would've been allocated after the snapshot was created.
  2. The transaction ID is less than the snapshots recorded minimum transaction ID: If satisfied, the transaction ID is visible, as these would've been allocated and committed before the snapshot was created.
  3. The transaction ID exists in the snapshots recorded concurrent transaction list: If found, the transaction ID is invisible, as this ID wasn't committed at the time the snapshot was created.
  4. Otherwise the ID is visible.

The early ordering of checking whether the transaction ID sits outside the maximum and minimum bounds is an important detail since the concurrent transaction list can be empty i.e. snapshot was taken at a time when no concurrent transactions were running.

Snapshots & Checkpoints

Checkpoints require a snapshot to write a transactionally consistent view of the data. A checkpoint maintains its own special global transaction and snapshot state. This being independent from the application's running transactions.

When checkpoints are running, application transactions using snapshots will also store the checkpoints transaction ID as a concurrent transaction. This allowing a snapshot to ignore any uncommitted changes the checkpoint has written to the metadata.

Snapshot Read-uncommitted & Modifies

It is possible that a read-uncommitted reader can not reconstruct a full value. This is because a snapshot isolation writer can abort the updates in parallel and leave the reader with an update list that does not contain enough information to reconstruct the full value. It is impossible to distinguish if an aborted modify or update happened prior to the call of the function, or if it is being done in parallel. In this case, we will return back to the user with a WT_ROLLBACK error. Once the user reads the record again, the update chain will contain the aborted operations already.