diff --git a/txnkv/transaction/prewrite.go b/txnkv/transaction/prewrite.go index a6eeafb3e5..21b84e8a39 100644 --- a/txnkv/transaction/prewrite.go +++ b/txnkv/transaction/prewrite.go @@ -449,6 +449,7 @@ func (action actionPrewrite) handleSingleBatch( zap.Uint64("session", c.sessionID), zap.Uint64("txnID", c.startTS), zap.Stringer("lock", lock), + zap.Stringer("policy", c.txn.prewriteEncounterLockPolicy), ) logged[lock.TxnID] = struct{}{} } @@ -457,7 +458,8 @@ func (action actionPrewrite) handleSingleBatch( // Pessimistic transactions don't need such an optimization. If this key needs a pessimistic lock, // TiKV will return a PessimisticLockNotFound error directly if it encounters a different lock. Otherwise, // TiKV returns lock.TTL = 0, and we still need to resolve the lock. - if lock.TxnID > c.startTS && !c.isPessimistic { + if (lock.TxnID > c.startTS && !c.isPessimistic) || + c.txn.prewriteEncounterLockPolicy == NoResolvePolicy { return tikverr.NewErrWriteConflictWithArgs( c.startTS, lock.TxnID, diff --git a/txnkv/transaction/txn.go b/txnkv/transaction/txn.go index daccbe087c..d6b1e6b9f7 100644 --- a/txnkv/transaction/txn.go +++ b/txnkv/transaction/txn.go @@ -117,6 +117,28 @@ type TxnOptions struct { PipelinedMemDB bool } +// PrewriteEncounterLockPolicy specifies the policy when prewrite encounters locks. +type PrewriteEncounterLockPolicy int + +const ( + // TryResolvePolicy is the default one: try to resolve those locks with smaller startTS. + TryResolvePolicy PrewriteEncounterLockPolicy = iota + // NoResolvePolicy means do not resolve, but return write conflict errors directly. + // This can be used to let the upper layer choose to retry in pessimistic mode. + NoResolvePolicy +) + +func (p PrewriteEncounterLockPolicy) String() string { + switch p { + case TryResolvePolicy: + return "TryResolvePolicy" + case NoResolvePolicy: + return "NoResolvePolicy" + default: + return "Unknown" + } +} + // KVTxn contains methods to interact with a TiKV transaction. type KVTxn struct { snapshot *txnsnapshot.KVSnapshot @@ -172,6 +194,8 @@ type KVTxn struct { isPipelined bool pipelinedCancel context.CancelFunc + + prewriteEncounterLockPolicy PrewriteEncounterLockPolicy } // NewTiKVTxn creates a new KVTxn. @@ -472,6 +496,11 @@ func (txn *KVTxn) SetAssertionLevel(assertionLevel kvrpcpb.AssertionLevel) { txn.assertionLevel = assertionLevel } +// SetPrewriteEncounterLockPolicy specifies the behavior when prewrite encounters locks. +func (txn *KVTxn) SetPrewriteEncounterLockPolicy(policy PrewriteEncounterLockPolicy) { + txn.prewriteEncounterLockPolicy = policy +} + // IsPessimistic returns true if it is pessimistic. func (txn *KVTxn) IsPessimistic() bool { return txn.isPessimistic