Skip to content

Commit 1c32853

Browse files
ekexiumzeminzhou
authored andcommitted
txn: skips resolving lock in auto commit optimistic statement (pingcap#58676)
close pingcap#58675
1 parent 95d9f12 commit 1c32853

File tree

5 files changed

+42
-12
lines changed

5 files changed

+42
-12
lines changed

pkg/kv/option.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ const (
116116
SessionID
117117
// BackgroundGoroutineLifecycleHooks is the hooks to track the start and end of background goroutine
118118
BackgroundGoroutineLifecycleHooks
119+
// PrewriteEncounterLockPolicy is the policy to handle lock conflict during prewrite
120+
PrewriteEncounterLockPolicy
119121
)
120122

121123
// TxnSizeLimits is the argument type for `SizeLimits` option

pkg/session/txn.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -665,23 +665,23 @@ type txnFuture struct {
665665
}
666666

667667
func (tf *txnFuture) wait() (kv.Transaction, error) {
668+
options := []tikv.TxnOption{tikv.WithTxnScope(tf.txnScope)}
668669
startTS, err := tf.future.Wait()
669670
failpoint.Inject("txnFutureWait", func() {})
670671
if err == nil {
671-
if tf.pipelined {
672-
return tf.store.Begin(tikv.WithTxnScope(tf.txnScope), tikv.WithStartTS(startTS), tikv.WithDefaultPipelinedTxn())
672+
options = append(options, tikv.WithStartTS(startTS))
673+
} else {
674+
if config.GetGlobalConfig().Store == config.StoreTypeUniStore {
675+
return nil, err
673676
}
674-
return tf.store.Begin(tikv.WithTxnScope(tf.txnScope), tikv.WithStartTS(startTS))
675-
} else if config.GetGlobalConfig().Store == config.StoreTypeUniStore {
676-
return nil, err
677+
logutil.BgLogger().Warn("wait tso failed", zap.Error(err))
677678
}
678679

679-
logutil.BgLogger().Warn("wait tso failed", zap.Error(err))
680-
// It would retry get timestamp.
681680
if tf.pipelined {
682-
return tf.store.Begin(tikv.WithTxnScope(tf.txnScope), tikv.WithDefaultPipelinedTxn())
681+
options = append(options, tikv.WithDefaultPipelinedTxn())
683682
}
684-
return tf.store.Begin(tikv.WithTxnScope(tf.txnScope))
683+
684+
return tf.store.Begin(options...)
685685
}
686686

687687
// HasDirtyContent checks whether there's dirty update on the given table.

pkg/sessiontxn/isolation/base.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,21 @@ func (p *baseTxnContextProvider) SetOptionsBeforeCommit(
614614
if commitTSChecker != nil {
615615
txn.SetOption(kv.CommitTSUpperBoundCheck, commitTSChecker)
616616
}
617+
618+
// Optimization:
619+
// If an auto-commit optimistic transaction can retry in pessimistic mode,
620+
// do not resolve locks when prewrite.
621+
// 1. safety: The locks can be resolved later when it retries in pessimistic mode.
622+
// 2. benefit: In high-contention scenarios, pessimistic transactions perform better.
623+
prewriteEncounterLockPolicy := transaction.TryResolvePolicy
624+
if sessVars.TxnCtx.CouldRetry &&
625+
sessVars.IsAutocommit() &&
626+
!sessVars.InTxn() &&
627+
!sessVars.TxnCtx.IsPessimistic {
628+
prewriteEncounterLockPolicy = transaction.NoResolvePolicy
629+
}
630+
txn.SetOption(kv.PrewriteEncounterLockPolicy, prewriteEncounterLockPolicy)
631+
617632
return nil
618633
}
619634

pkg/sessiontxn/isolation/optimistic.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,32 @@ func (p *OptimisticTxnContextProvider) ResetForNewTxn(sctx sessionctx.Context, c
4646
p.getStmtForUpdateTSFunc = p.getTxnStartTS
4747
}
4848

49-
func (p *OptimisticTxnContextProvider) onTxnActive(_ kv.Transaction, tp sessiontxn.EnterNewTxnType) {
49+
func (p *OptimisticTxnContextProvider) onTxnActive(
50+
txn kv.Transaction,
51+
tp sessiontxn.EnterNewTxnType,
52+
) {
5053
sessVars := p.sctx.GetSessionVars()
51-
sessVars.TxnCtx.CouldRetry = isOptimisticTxnRetryable(sessVars, tp)
54+
sessVars.TxnCtx.CouldRetry = isOptimisticTxnRetryable(sessVars, tp, txn.IsPipelined())
5255
}
5356

5457
// isOptimisticTxnRetryable (if returns true) means the transaction could retry.
5558
// We only consider retry in this optimistic mode.
5659
// If the session is already in transaction, enable retry or internal SQL could retry.
5760
// If not, the transaction could always retry, because it should be auto committed transaction.
5861
// Anyway the retry limit is 0, the transaction could not retry.
59-
func isOptimisticTxnRetryable(sessVars *variable.SessionVars, tp sessiontxn.EnterNewTxnType) bool {
62+
func isOptimisticTxnRetryable(
63+
sessVars *variable.SessionVars,
64+
tp sessiontxn.EnterNewTxnType,
65+
isPipelined bool,
66+
) bool {
6067
if tp == sessiontxn.EnterNewTxnDefault {
6168
return false
6269
}
6370

71+
if isPipelined {
72+
return false
73+
}
74+
6475
// If retry limit is 0, the transaction could not retry.
6576
if sessVars.RetryLimit == 0 {
6677
return false

pkg/store/driver/txn/txn_driver.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ func (txn *tikvTxn) SetOption(opt int, val any) {
311311
txn.KVTxn.SetSessionID(val.(uint64))
312312
case kv.BackgroundGoroutineLifecycleHooks:
313313
txn.KVTxn.SetBackgroundGoroutineLifecycleHooks(val.(transaction.LifecycleHooks))
314+
case kv.PrewriteEncounterLockPolicy:
315+
txn.KVTxn.SetPrewriteEncounterLockPolicy(val.(transaction.PrewriteEncounterLockPolicy))
314316
}
315317
}
316318

0 commit comments

Comments
 (0)