160 Snapshot Isolation
Snapshot isolation allows a logical operation to read a stable database state while other transactions publish newer states. At the start of the operation, the implementation obtains a snapshot identifying the committed state visible to that operation. Every subsequent database read made by the operation uses that same snapshot.
A snapshot is an implementation facility, not a value exposed in the Predica logical model. Predica expressions observe values and predicate extensions; they do not observe versions, object identifiers, map roots, or transaction sequence numbers.
One logical operation, one snapshot
All objects reached during one logical operation must be resolved through the same snapshot. This includes objects loaded only after navigation reaches them. Lazy loading must not cause a later object to be read from a newer committed state than an object loaded earlier in the same operation.
operation snapshot S100
load A → rendition visible at S100
navigate A.b
load B later → rendition visible at S100
This rule is particularly important for large object graphs such as
TiledImage. Loading one tile on demand does not advance the snapshot. If
another transaction replaces a tile while the image is being read, the reader
continues to observe the rendition selected by its existing snapshot.
Transaction views
A writing transaction reads from a committed base snapshot together with its own updates. Its intermediate changes are not visible to other operations. Commit validates the final transaction state and makes the transaction's changes visible as one new committed state. An operation that already holds an older snapshot continues to observe its existing state.
Snapshot isolation alone is not equivalent to serial execution: transactions that update disjoint objects can still make decisions from the same older snapshot. Predica avoids relying on snapshot isolation alone for transactional invariants. Updates are confined to a partition, and the partition's ownership or serialisation mechanism remains responsible for ensuring that accepted commits satisfy its constraints.
The versioned OID maps, write-conflict detection, checkpoint roots, and transaction deltas that can implement this behaviour belong to the persistent object store and are described in Persistent Object Store.
Derived attributes and caches
A materialised derived attribute is a cache of a logically derived value. A cached result may be reused only when it corresponds to the snapshot and input renditions from which it was derived. A result computed from a newer input must not be introduced into an older snapshot merely because it is already available in memory.
Implementations may key cached results by snapshot, by the versions of their dependencies, or by another scheme with the same effect. Publishing an update invalidates or supersedes affected cached results for later snapshots without altering results still reachable through retained snapshots.
Snapshot lifetime
A snapshot remains valid until its logical operation releases it. While it is retained, every value reachable through it must remain available. How the persistent object store retains and eventually reclaims the required physical versions is described in Persistent Object Store.