MVCC makes reads lock-free by making them a comparison problem. Every row version carries two transaction IDs — xmin, who created it, and xmax, who deleted it — and the visibility check is a series of comparisons between those markers and the reader's snapshot. This diagram shows the actual decision procedure a scan runs per version: is the creator committed and old enough? Is the deleter committed? Does either match my own transaction?
The elegance is that the snapshot is just data — a list of in-flight transaction IDs captured at one instant — so visibility never requires waiting on anyone. A writer committing mid-scan simply never appears in that snapshot's in-flight set. The cost is version accumulation: old versions linger until no snapshot can see them, which is exactly what vacuum exists to reclaim. Understanding the check in this order — xid, snapshot, xmin, xmax — makes every concurrency question answerable.