As per my understanding, postgres uses two additional fields Xmin and Xmax to implement mvcc, Lets say we have Employee table with id and name columns.
Below are some crud operations and how they are working concurrently(considering isolation level = READ_COMMITTED) and the question is when and where actual lock is acquired.
- Insert -> A new transaction inserts a new record which is not visible to other transactions until it is committed, so no issues in this case and no lock or version control is required. Lets say id = 1, name = "aa" gets inserted. Postgres adds 2 additional columns for mvcc Xmin = current txn id (lets say 100) and Xmax = 0/null.
id | name | Xmin | Xmax
------------------------------
1 | aa | 100 | null
Update with concurrent Read -
a). A new transaction started to update name to "bb" (for id = 1). At the same time there is another transaction started to read the same data.
b). A new Tuple (immutable object in postgres representing a row) gets created with Xmin = current transaction id (Lets say 200) and Xmax = null along with id = 1, name = bb. Also the older version of id = 1 gets updated to have Xmax = 200. Read transaction sees the older version of data with Xmin = 100 and returns. Is there any locking required in this case ? I think no but it might to update the older tuple's Xmax.
Below is same record with multiple versions(just for explanation purpose) with latest version having Xmax = null.
id | name | Xmin | Xmax
------------------------------
1 | aa | 100 | 200
1 | bb | 200 | null
Update with concurrent Update -
a). Transaction (with txn id = 300) started to update id = 1 to name = cc. Another transaction(txn id = 400) started to update the same record (id = 1) to name = dd. If this scenario also proceeds in same way by creating new tuple and marking old tuple's Xmax then i think it would create problems because both 300 and 400 will create a new tuple and mark the old tuple's Xmax = txn id. An update could loose in this case.
In this scenario does exclusive lock is acquired by first txn and other concurrent update txns wait until any ongoing txn is completed or there is some other way in which postgres handles it ?