How Does Multiversion Concurrency Control Avoid Blocking?
Multiversion Concurrency Control, commonly known as MVCC, is a database concurrency method that allows read transactions and write transactions to execute simultaneously without blocking each other. Instead of overwriting data in place and forcing readers to wait for locks, the system maintains multiple historical versions of each data item. By assigning each transaction a consistent snapshot of the database based on timestamps or transaction IDs, readers can safely access older committed versions while writers create new versions in parallel.
The Core Mechanism of Multiple Versions
In traditional locking systems, a write operation acquires an exclusive lock on a record, which forces any concurrent read operation to wait until the write completes. MVCC eliminates this contention by treating data updates as the creation of new versions rather than in-place modifications.
When a transaction modifies a record, the database management system preserves the existing version and writes the updated value to a new version. Each version is tagged with metadata, typically including a creation timestamp \(t_{\text{create}}\) and an expiration or deletion timestamp \(t_{\text{expire}}\).
Snapshot Isolation and Visibility Rules
To ensure that a read transaction sees a consistent state of the database, MVCC assigns each transaction a unique, monotonically increasing transaction identifier or start timestamp \(T_{\text{start}}\). When a reader queries a data item, the database evaluates the available versions against visibility rules:
- The version must have been created by a transaction that committed before \(T_{\text{start}}\).
- The version must not have been expired or deleted by a transaction that committed before \(T_{\text{start}}\).
Mathematically, a version \(V\) is visible to a read transaction with start timestamp \(T_{\text{start}}\) if:
\[t_{\text{create}}(V) \le T_{\text{start}} < t_{\text{expire}}(V)\]
Because these visibility checks rely on immutable committed metadata, the reader never needs to acquire a shared lock on the record. Even if a concurrent writer is actively creating a newer version \(V_{\text{new}}\) with \(t_{\text{create}}(V_{\text{new}}) > T_{\text{start}}\), the reader simply ignores the uncommitted or newer version and reads \(V\).
Handling Concurrent Writes and Garbage Collection
While readers never block writers and writers never block readers, two concurrent write transactions attempting to modify the same record still require coordination. Most MVCC implementations use first-committer-wins or row-level write locks to prevent lost updates. If a second writer tries to update a record that has already been modified by a concurrent transaction, it either waits for the first writer or aborts and retries.
Maintaining multiple versions of data over time increases storage overhead. To reclaim space, MVCC systems run background garbage collection or vacuuming processes. These processes identify and remove obsolete versions whose \(t_{\text{expire}}\) is older than the \(T_{\text{start}}\) of the oldest active transaction in the system, ensuring that no running reader still needs them.