We are mostly following the Multi-Version Concurrency Control system described in thtransactionsis HyperDB related paper.
The goal of this chapter is to give a brief explanation about how the MVCC works. For detailed explanation and reasoning, please consult the paper.
When a transaction starts, it gets a start timestamp. The start timestamp indicate when a transaction is started regarding to other transactions commit timestamp. Each transaction receives a commit timestamp when it is committed. The two timestamps are generated using a single counter. This mean using the timestamps we can always decide which transaction is started before or whether any of them committed before the other started. On top of the two mentioned timestamps, each transaction has a transaction id. It is always true that all of the transaction ids are greater than all of the start and commit timestamps. The transaction id is somewhat different than the start and commit timestamps, but because it is often used in the same manner, let’s consider it also to be a timestamp.
In our implementation (and also in the paper) start and commit timestamps start from 0 and transaction ids are start from 2^63.
When a transaction modifies an object, then on top modifying the object in place, it also creates a delta object which described how to undo the changes of the transaction. These delta object can be used for multiple things:
Each delta consists of three important part in theory:
x
property to original_value
” and similar things)When a transaction wants to read an object, it has to check its delta chain to make sure it recover the correct version of the object. To achieve this in snapshot isolation mode, a transactions needs to apply the deltas that are committed before the transaction started. This can be checked easily by comparing the timestamp of a delta and the start timestamp of a transaction. For deltas that are not committed, the timestamp is a transaction id, which is always bigger than any start timestamp. For deltas that are committed, the timestamp is the commit timestamp of the transaction, which can be used to determine the order of the start of current transaction and the commit of the transaction that created the delta. Based on these, if a delta’s timestamp is larger than the start timestamp of the transaction, then the delta has to be applied to revert back the changes of the object to the state when it should be at start time of the transaction. This functionality is described in mvcc.hpp
in the ApplyDeltasForRead
function.
Similarly, for read committed isolation level, all the uncommitted deltas has to be applied (delta’s timestamp greater or equal than the smallest transaction id). For read uncommitted isolation level, none of the deltas should be applied.
When a transaction wants to write an object using any isolation level, a very similar thing has to done to figure out whether the transaction is allowed to modify the object or not. The transaction is free to modify the object, when the object