Lock Resolver
Last updated
Was this helpful?
Last updated
Was this helpful?
As we described in , TiDB's transaction system is based on Google's algorithm. Which makes it necessary to resolve locks when a reading transaction meets locked keys or during .
So we introduced Lock Resolver in TiDB to resolve locks.
Lock Resolver is a quiet simple struct:
The store
field is used to send requests to a region on TiKV. And the fields inside the mu
are used to cache the resolved transactions' status, which is used to speed up the transaction status checking.
Now let's see the real important part: the lock resolving process.
Basically, the resolving process is in 2 steps:
For each lock, get the commit status of the corresponding transaction.
Send ResolveLock
cmd to tell the storage layer to do the resolve work.
In the following several paragraphs, we will give you some brief introduction about each step.
Instead of keeping all rollbacks in write column family when a key rollbacked for several times, this PR collapse continuous rollbacks, and only keep the latest rollback.
After we have pessimistic lock in TiKV, if the rollback record of the primary lock is collapsed and TiKV receives stale acquire_pessimistic_lock and prewrite, the transaction will commit successfully even if secondary locks are rolled back. To solve this problem, we can prevent the rollback records of the primary key of pessimistic transactions from being collapsed. By setting the short value of these rollback records to "protected".
After understand these, you can finally understand the code:
There are three different kinds of locks we need to pay attention to when doing the resolving work:
When a resolve lock request reaches TiKV, depends on whether resolve_keys
field is empty or not, TiKV will do different things:
ResolveLockReadPhase + ResolveLock
This will triggered when resolve_keys
field is not set.
ResolveLockReadPhase
will scan keys and locks on them which should be resolved in a region, to prevent huge writes, we'll do the scan in batches (RESOLVE_LOCK_BATCH_SIZE
keys in a batch).
After each batch is read, a ResolveLock
command will be spawned to do the real resolve work.
In ResolveLock
, for each key and lock on it, depend on whether the transaction status is committed or not, we'll cleanup or commit it.
And then, TiKV will wake up the blocked transactions, and we are done.
ResolveLockLite
This will triggered when resolve_keys
field is set.
ResolveLockLite
is just a simplified version of ResolveLock
, which will do the resolve work on resolve_keys
on the request.
If you want to read all of the code, is a good place to start.
Related code is and .
just assemble a CheckTxnStatus
request and send it to the TiKV the primary key is located on. TiKV will return a , which represents the status of a transaction, like RolledBack
(the transaction has already been rolled back before), TtlExpire
(the transaction's is expired, TiKV just rolled it back), Committed
(the transaction was committed successfully before), etc. to TiDB.
basically delegate its work to with the information in the lock and add some retry and error handling logic.
As we showed above, we use a request to get the status of a transaction when resolving a lock.
The major processing logic can be found , this function is a little complex (mainly because the scheduling process in TiKV), I'll show you the basic idea with some simplified pseudo code with detailed comments, before that, there are several optimizations and related concepts we should know:
collapse continuous rollbacks ()
protect primary locks ()
gc_fence ()
See the super detailed comment .
After we get the transaction status with , if the transaction has been expired (either committed or rollbacked), we need to resolve the lock.
locks created by transactions This kind of lock will be resolved by , you can refer to for more information.
pessimistic locks created by This kind of lock will be resolved by , which just send to TiKV, with some retry and error handling logic.
optimistic locks created by This kind of lock will be resolved by , which just send to TiKV, with some retry and error handling logic.
When , it is possible that a transaction meet other transaction's lock when it is trying to acquire the lock. In this situation, we should try to resolve the old transaction's lock first.
When reading from TiKV, eg. when , we should resolve the lock we met first.
When doing , see for detail.
This document talked about the data structure of Lock Resolver in TiDB, and its working process and usage. You can combine this with other parts of our to have a deeper understanding.