From aecc3421dcdcbb80571a8a1f76fb6bdc762300a8 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 7 Nov 2019 13:59:39 +0800 Subject: [PATCH] executor: do update forUpdateTs for err path (#13218) --- executor/adapter.go | 15 ++++++++------- store/tikv/txn.go | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/executor/adapter.go b/executor/adapter.go index b2f69f23af..02906e0fb0 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -600,20 +600,21 @@ func (a *ExecStmt) handlePessimisticLockError(ctx context.Context, err error) (E if conflictCommitTS > forUpdateTS { newForUpdateTS = conflictCommitTS } - } else if terror.ErrorEqual(err, tikv.ErrLockAcquireFailAndNoWaitSet) { + } else { + // this branch if err not nil, always update forUpdateTS to avoid problem described below // for nowait, when ErrLock happened, ErrLockAcquireFailAndNoWaitSet will be returned, and in the same txn // the select for updateTs must be updated, otherwise there maybe rollback problem. // begin; select for update key1(here ErrLocked or other errors(or max_execution_time like util), // key1 lock not get and async rollback key1 is raised) // select for update key1 again(this time lock succ(maybe lock released by others)) // the async rollback operation rollbacked the lock just acquired - newForUpdateTS, tsErr := a.GetTimestampWithRetry(ctx) - if tsErr != nil { - return nil, tsErr + if err != nil { + newForUpdateTS, tsErr := a.GetTimestampWithRetry(ctx) + if tsErr != nil { + return nil, tsErr + } + txnCtx.SetForUpdateTS(newForUpdateTS) } - txnCtx.SetForUpdateTS(newForUpdateTS) - return nil, err - } else { return nil, err } if a.retryCount >= config.GetGlobalConfig().PessimisticTxn.MaxRetryCount { diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 0d26ac5dfb..1efaa79935 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -381,7 +381,7 @@ func (txn *tikvTxn) rollbackPessimisticLocks() error { return txn.committer.pessimisticRollbackKeys(NewBackoffer(context.Background(), cleanupMaxBackoff), txn.lockKeys) } -// lockWaitTime in ms, except that 0 means always wait lock, 1 means nowait lock +// lockWaitTime in ms, except that kv.LockAlwaysWait(0) means always wait lock, kv.LockNowait(-1) means nowait lock func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keysInput ...kv.Key) error { // Exclude keys that are already locked. keys := make([][]byte, 0, len(keysInput))