Optimistic Transaction
Under the optimistic transaction model, modification conflicts are regarded as part of the transaction commit. TiDB cluster uses the optimistic transaction model by default before version 3.0.8, uses pessimistic transaction model after version 3.0.8. System variable tidb_txn_mode controls TiDB uses optimistic transaction mode or pessimistic transaction mode.
This document talks about the implementation of optimistic transaction in TiDB. It is recommended that you have learned about the principles of optimistic transaction.
This document refers to the code of TiDB v5.2.1
Begin Optimistic Transaction
The main function stack to start an optimistic transaction is as followers.
(a *ExecStmt) Exec
(a *ExecStmt) handleNoDelay
(a *ExecStmt) handleNoDelayExecutor
Next
(e *SimpleExec) Next
(e *SimpleExec) executeBeginThe function (e *SimpleExec) executeBegin do the main work for a "BEGIN" statement,The important comment and simplified code is as followers. The completed code is here .
/*
Check the syntax "start transaction read only" and "as of timestamp" used correctly.
If stale read timestamp was set, creates a new stale read transaction and sets "in transaction" state, and return.
create a new transaction and set some properties like snapshot, startTS etc
*/
func (e *SimpleExec) executeBegin(ctx context.Context, s *ast.BeginStmt) error {
if s.ReadOnly {
// the statement "start transaction read only" must be used with tidb_enable_noop_functions is true
// the statement "start transaction read only as of timestamp" can be used Whether tidb_enable_noop_functions is true or false,but that tx_read_ts mustn't be set.
// the statement "start transaction read only as of timestamp" must ensure the timestamp is in the legal safe point range
enableNoopFuncs := e.ctx.GetSessionVars().EnableNoopFuncs
if !enableNoopFuncs && s.AsOf == nil {
return expression.ErrFunctionsNoopImpl.GenWithStackByArgs("READ ONLY")
}
if s.AsOf != nil {
if e.ctx.GetSessionVars().TxnReadTS.PeakTxnReadTS() > 0 {
return errors.New("start transaction read only as of is forbidden after set transaction read only as of")
}
}
}
// process stale read transaction
if e.staleTxnStartTS > 0 {
// check timestamp of stale read correctly
if err := e.ctx.NewStaleTxnWithStartTS(ctx, e.staleTxnStartTS); err != nil {
return err
}
// ignore tidb_snapshot configuration if in stale read transaction
vars := e.ctx.GetSessionVars()
vars.SetSystemVar(variable.TiDBSnapshot, "")
// set "in transaction" state and return
vars.SetInTxn(true)
return nil
}
/* If BEGIN is the first statement in TxnCtx, we can reuse the existing transaction, without the need to call NewTxn, which commits the existing transaction and begins a new one. If the last un-committed/un-rollback transaction is a time-bounded read-only transaction, we should always create a new transaction. */
txnCtx := e.ctx.GetSessionVars().TxnCtx
if txnCtx.History != nil || txnCtx.IsStaleness {
err := e.ctx.NewTxn(ctx)
}
// set "in transaction" state
e.ctx.GetSessionVars().SetInTxn(true)
// create a new transaction and set some properties like snapshot, startTS etc.
txn, err := e.ctx.Txn(true)
// set Linearizability option
if s.CausalConsistencyOnly {
txn.SetOption(kv.GuaranteeLinearizability, false)
}
return nil
}DML Executed In Optimistic Transaction
There are three kinds of DML operations, such as update, delete and insert. For simplicity, This article only describes the update statement execution process. DML mutations are not sended to tikv directly, but buffered in TiDB temporarily, commit operation make the mutations effective at last.
The main function stack to execute an update statement such as "update t1 set id2 = 2 where pk = 1" is as followers.
(e *UpdateExec) updateRows
The function (e *UpdateExec) updateRows does the main work for update statement. The important comment and simplified code are as followers. The completed code is here .
Commit Optimistic Transaction
Committing transaction includes "prewrite" and "commit" two phases that are explained separately below. The function (c *twoPhaseCommitter) execute does the main work for committing transaction. The important comment and simplified code are as followers. The completed code is here .
prewrite
The entry function to prewrite a transaction is (c *twoPhaseCommitter) prewriteMutations which calls the function (batchExe *batchExecutor) process to do it. The function (batchExe *batchExecutor) process calls (batchExe *batchExecutor) startWorker to prewrite evenry batch parallelly. The function (batchExe *batchExecutor) startWorker calls (action actionPrewrite) handleSingleBatch to prewrite a single batch.
(batchExe *batchExecutor) process
The important comment and simplified code are as followers. The completed code is here .
(batchExe *batchExecutor) startWorker
The important comment and simplified code are as followers. The completed code is here .
(action actionPrewrite) handleSingleBatch
The important comment and simplified code are as followers. The completed code is here .
commit
The entry function of commiting a transaction is (c *twoPhaseCommitter) commitMutations which calls the function (c *twoPhaseCommitter) doActionOnGroupMutations to do it. The batch of primary key will be committed first, then the function (batchExe *batchExecutor) process calls (batchExe *batchExecutor) startWorker to commit the rest batches parallelly and asynchronously. The function (batchExe *batchExecutor) startWorker calls (actionCommit) handleSingleBatch to commit a single batch.
(c *twoPhaseCommitter) doActionOnGroupMutations
The important comment and simplified code are as followers. The completed code is here .
(batchExe *batchExecutor) process
The function (c *twoPhaseCommitter) doActionOnGroupMutations calls (c *twoPhaseCommitter) doActionOnBatches to do the second phase of commit. The function (c *twoPhaseCommitter) doActionOnBatches calls (batchExe *batchExecutor) process to do the main work.
The important comment and simplified code of function (batchExe *batchExecutor) process are as mentioned above in prewrite part . The completed code is here .
(actionCommit) handleSingleBatch
The function (batchExe *batchExecutor) process calls the function (actionCommit) handleSingleBatch to send commit request to all tikv nodes.
The important comment and simplified code are as followers. The completed code is here .
Last updated
Was this helpful?