-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
executor: support innodb_lock_wait_timeout for pessimistic transaction #13103
Conversation
324fea2
to
022273d
Compare
Codecov Report
@@ Coverage Diff @@
## master #13103 +/- ##
===========================================
Coverage 80.6801% 80.6801%
===========================================
Files 468 468
Lines 113153 113153
===========================================
Hits 91292 91292
Misses 15039 15039
Partials 6822 6822 |
session/pessimistic_test.go
Outdated
tk3.MustExec("begin pessimistic") | ||
start := time.Now() | ||
_, err := tk3.Exec("select * from tk where c1 = 1 for update") | ||
c.Check(time.Since(start), GreaterEqual, time.Duration(1*time.Second)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to check the duration is not too long.
022273d
to
5ac2253
Compare
sessionctx/variable/session.go
Outdated
@@ -447,6 +447,9 @@ type SessionVars struct { | |||
isolationReadEngines map[kv.StoreType]struct{} | |||
|
|||
PlannerSelectBlockAsName []ast.HintTable | |||
|
|||
// Lock wait timeout for pessimistic transaction in milliseconds, `innodb_lock_wait_timeout` is in seconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put is in seconds
at the last is too easy to be misunderstood as LockWaitTimeout
is in seconds.
sessionctx/variable/session.go
Outdated
@@ -447,6 +447,9 @@ type SessionVars struct { | |||
isolationReadEngines map[kv.StoreType]struct{} | |||
|
|||
PlannerSelectBlockAsName []ast.HintTable | |||
|
|||
// Lock wait timeout for pessimistic transaction in milliseconds, `innodb_lock_wait_timeout` is in seconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Lock wait timeout for pessimistic transaction in milliseconds, `innodb_lock_wait_timeout` is in seconds | |
// LockWaitTimeout is used for pessimistic transaction in milliseconds, `innodb_lock_wait_timeout` is in seconds. |
executor/executor.go
Outdated
@@ -815,7 +815,7 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { | |||
} | |||
return nil | |||
} | |||
var lockWaitTime = kv.LockAlwaysWait | |||
var lockWaitTime = e.ctx.GetSessionVars().LockWaitTimeout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var lockWaitTime = e.ctx.GetSessionVars().LockWaitTimeout | |
lockWaitTime := e.ctx.GetSessionVars().LockWaitTimeout |
if !c.store.oracle.IsExpired(lock.TxnID, lock.TTL) { | ||
return ErrLockAcquireFailAndNoWaitSet | ||
} | ||
} else if action.lockWaitTime == kv.LockAlwaysWait { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to handle LockAlwaysWait
, innodb_wait_timeout
is always positive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@coocood some inner usages which calls doLockKeys
(like RecoverIndexExec
, addIndexWorker
) will set this param LockAlwaysWait
if !c.store.oracle.IsExpired(lock.TxnID, lock.TTL) { | ||
return ErrLockAcquireFailAndNoWaitSet | ||
} | ||
} else if action.lockWaitTime == kv.LockAlwaysWait { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
} else if action.lockWaitTime == kv.LockAlwaysWait { | |
} else if action.lockWaitTime != kv.LockAlwaysWait { |
then do something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current we have 3 paths(negative, 0, positive value), I think it's more clear to make them like noodle style, and we just need to add/remove one more else if
path if we want to modify the protocol
@@ -812,6 +816,9 @@ func (s *SessionVars) SetSystemVar(name string, val string) error { | |||
case MaxExecutionTime: | |||
timeoutMS := tidbOptPositiveInt32(val, 0) | |||
s.MaxExecutionTime = uint64(timeoutMS) | |||
case InnodbLockWaitTimeout: | |||
lockWaitSec := tidbOptInt64(val, DefInnodbLockWaitTimeout) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to validate the range.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is done in function ValidateSetSystemVar
case InnodbLockWaitTimeout:
return checkUInt64SystemVar(name, value, 1, 1073741824, vars)
mysql> set global innodb_lock_wait_timeout = 0;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------+
| Warning | 1292 | Truncated incorrect innodb_lock_wait_timeout value: '0' |
+---------+------+---------------------------------------------------------+
1 row in set (0.00 sec)
tk3.MustExec("set innodb_lock_wait_timeout = 1") | ||
tk3.MustQuery(`show variables like "innodb_lock_wait_timeout"`).Check(testkit.Rows("innodb_lock_wait_timeout 1")) | ||
|
||
tk2.MustExec("set @@autocommit = 0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why set autocommit here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set this before next begin
statement below
@@ -676,6 +676,7 @@ func (action actionPessimisticLock) handleSingleBatch(c *twoPhaseCommitter, bo * | |||
IsFirstLock: c.isFirstLock, | |||
WaitTimeout: action.lockWaitTime, | |||
}, pb.Context{Priority: c.priority, SyncLog: c.syncLog}) | |||
lockWaitStartTime := time.Now() | |||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to update the req.WaitTimeout
. so if the wait timeout is less than 3s,we can return sooner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
roger
store/tikv/2pc.go
Outdated
return ErrLockAcquireFailAndNoWaitSet | ||
if lock.LockType == pb.Op_PessimisticLock { | ||
if action.lockWaitTime == kv.LockNoWait { | ||
// the pessimistic lock found could be lock left behind(timeout but not recycled yet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to improve the English of this comment.
store/tikv/2pc.go
Outdated
} else if action.lockWaitTime == kv.LockAlwaysWait { | ||
// do nothing but keep wait | ||
} else { | ||
// user has set the `InnodbLockWaitTimeout`, check timeout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to improve the English of this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
LGTM |
@tiancaiamao @lysu PTAL |
@youjiali1995 PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
/merge |
/run-all-tests |
cherry pick to release-3.0 failed |
It seems that, not for sure, we failed to cherry-pick this commit to release-3.0. Please comment '/run-cherry-picker' to try to trigger the cherry-picker if we did fail to cherry-pick this commit before. @cfzjywxk PTAL. |
What problem does this PR solve?
make
innodb_lock_wait_timeout
work for pessimistic transactions in tidbin MySQL, this is a system variable to set lock wait time for transactions,
The length of time in seconds an InnoDB transaction waits for a row lock before giving up. The default value is 50 seconds. A transaction that tries to access a row that is locked by another InnoDB transaction waits at most this many seconds for write access to the row before issuing the following error:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
When a lock wait timeout occurs, the current statement is rolled back (not the entire transaction).
mysql-doc
What is changed and how it works?
innodb_lock_wait_timeout
effective,the default value is same with mysqlErrLocked
error from kv, and report lock wait timout error if wait time greater thanlockWaitTime
, the current statement will be rollbacked like mysql behaviorsinnodb_lock_wait_timeout
does affect only user sessions dmlsTODO:
handlePessimiticError
to always update forforUpdateTs
Check List
Tests
Code changes
Side effects
Related changes
Release note