Skip to content

Commit d7764b5

Browse files
AliSQLAliSQL
authored andcommitted
[Feature] Issue#8: SELECT FOR UPDATE WAIT
Summary: -------- The feature provides a way to set lock wait timeout for some statement. Usage: ------ 1.select ... for update [wait [n]|no_wait] 2.select ... lock in share mode [wait [n]|no_wait] 3.lock table ... [wait [n]|no_wait] no_wait: the query not wait for locks, instead of return immeditly, and print "ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction;" wait [n]: n is wait time in second, after wait n seconds for locks, return and print errors;
1 parent 4c9d1c7 commit d7764b5

16 files changed

Lines changed: 277 additions & 10 deletions

include/mysql/plugin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ int thd_in_lock_tables(const MYSQL_THD thd);
553553
int thd_tablespace_op(const MYSQL_THD thd);
554554
long long thd_test_options(const MYSQL_THD thd, long long test_options);
555555
int thd_sql_command(const MYSQL_THD thd);
556+
long long thd_wait_time(const MYSQL_THD thd);
556557
const char *thd_proc_info(MYSQL_THD thd, const char *info);
557558
void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton);
558559
void thd_storage_lock_wait(MYSQL_THD thd, long long value);

include/mysql/plugin_audit.h.pp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
int thd_tablespace_op(const void* thd);
226226
long long thd_test_options(const void* thd, long long test_options);
227227
int thd_sql_command(const void* thd);
228+
long long thd_wait_time(const void* thd);
228229
const char *thd_proc_info(void* thd, const char *info);
229230
void **thd_ha_data(const void* thd, const struct handlerton *hton);
230231
void thd_storage_lock_wait(void* thd, long long value);

include/mysql/plugin_auth.h.pp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
int thd_tablespace_op(const void* thd);
226226
long long thd_test_options(const void* thd, long long test_options);
227227
int thd_sql_command(const void* thd);
228+
long long thd_wait_time(const void* thd);
228229
const char *thd_proc_info(void* thd, const char *info);
229230
void **thd_ha_data(const void* thd, const struct handlerton *hton);
230231
void thd_storage_lock_wait(void* thd, long long value);

include/mysql/plugin_ftparser.h.pp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
int thd_tablespace_op(const void* thd);
179179
long long thd_test_options(const void* thd, long long test_options);
180180
int thd_sql_command(const void* thd);
181+
long long thd_wait_time(const void* thd);
181182
const char *thd_proc_info(void* thd, const char *info);
182183
void **thd_ha_data(const void* thd, const struct handlerton *hton);
183184
void thd_storage_lock_wait(void* thd, long long value);

mysql-test/r/lock_no_wait.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
DROP TABLE IF EXISTS test.t1;
2+
CREATE TABLE test.t1 (c1 INT, c2 INT);
3+
INSERT INTO t1 (c1,c2) values (1,1),(2,2),(3,3),(4,4);
4+
# Connection con1
5+
LOCK TABLE test.t1 WRITE;
6+
# Connection con2
7+
LOCK TABLE test.t1 WRITE NO_WAIT;
8+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
9+
LOCK TABLE test.t1 WRITE WAIT 1;
10+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
11+
LOCK TABLE test.t1 WRITE WAIT 31536001;
12+
ERROR 42000: Variable 'wait_time' can't be set to the value of '31536001'
13+
LOCK TABLE test.t1 WRITE WAIT 10;
14+
# Connection con1
15+
UNLOCK TABLES;
16+
# Connection con2
17+
DROP TABLE test.t1;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
DROP TABLE IF EXISTS test.t1;
2+
CREATE TABLE test.t1 (c1 INT, c2 INT);
3+
INSERT INTO test.t1 (c1,c2) values (1,1),(2,2),(3,3),(4,4);
4+
# Connection con1
5+
LOCK TABLE test.t1 WRITE;
6+
# Connection con2
7+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE NO_WAIT;
8+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
9+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 1;
10+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
11+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 31536001;
12+
ERROR 42000: Variable 'wait_time' can't be set to the value of '31536001'
13+
# Connection con1
14+
INSERT INTO test.t1 VALUES(5,5);
15+
UNLOCK TABLES;
16+
set AUTOCOMMIT=0;
17+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE;
18+
# Connection con2
19+
set AUTOCOMMIT=0;
20+
SET INNODB_LOCK_WAIT_TIMEOUT=1;
21+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE;
22+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
23+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE NO_WAIT;
24+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
25+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 1;
26+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
27+
# Connection con1
28+
UPDATE test.t1 SET c2=5 WHERE c1=4;
29+
COMMIT;
30+
set AUTOCOMMIT=0;
31+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE;
32+
c1 c2
33+
4 5
34+
# Connection con2
35+
set AUTOCOMMIT=0;
36+
SET INNODB_LOCK_WAIT_TIMEOUT=1;
37+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 10;
38+
# Connection con1
39+
COMMIT;
40+
# Connection con2
41+
DROP TABLE test.t1;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# test for lock table .. wait/nowait , select .. for update wait/no_wait
2+
3+
# Save the initial number of concurrent sessions.
4+
--source include/count_sessions.inc
5+
--source include/have_innodb.inc
6+
7+
--disable_warnings
8+
DROP TABLE IF EXISTS test.t1;
9+
CREATE TABLE test.t1 (c1 INT, c2 INT);
10+
INSERT INTO test.t1 (c1,c2) values (1,1),(2,2),(3,3),(4,4);
11+
--enable_warnings
12+
13+
--echo # Connection con1
14+
connect(con1,localhost,root,,);
15+
LOCK TABLE test.t1 WRITE;
16+
17+
--echo # Connection con2
18+
connect(con2,localhost,root,,);
19+
# The following statement should hang because con1 is locking the table
20+
--error ER_LOCK_WAIT_TIMEOUT
21+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE NO_WAIT;
22+
--error ER_LOCK_WAIT_TIMEOUT
23+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 1;
24+
# wait time rang from 0 to 365*24*3600=31536000
25+
--error ER_WRONG_VALUE_FOR_VAR
26+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 31536001;
27+
28+
--echo # Connection con1
29+
connection con1;
30+
INSERT INTO test.t1 VALUES(5,5);
31+
UNLOCK TABLES;
32+
set AUTOCOMMIT=0;
33+
--disable_result_log
34+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE;
35+
--enable_result_log
36+
37+
--echo # Connection con2
38+
connection con2;
39+
set AUTOCOMMIT=0;
40+
SET INNODB_LOCK_WAIT_TIMEOUT=1;
41+
--error ER_LOCK_WAIT_TIMEOUT
42+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE;
43+
--error ER_LOCK_WAIT_TIMEOUT
44+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE NO_WAIT;
45+
--error ER_LOCK_WAIT_TIMEOUT
46+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 1;
47+
48+
--echo # Connection con1
49+
connection con1;
50+
UPDATE test.t1 SET c2=5 WHERE c1=4;
51+
COMMIT;
52+
set AUTOCOMMIT=0;
53+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE;
54+
55+
--echo # Connection con2
56+
connection con2;
57+
set AUTOCOMMIT=0;
58+
SET INNODB_LOCK_WAIT_TIMEOUT=1;
59+
--send
60+
--disable_result_log
61+
SELECT * FROM test.t1 WHERE c1=4 FOR UPDATE WAIT 10;
62+
63+
--echo # Connection con1
64+
connection con1;
65+
COMMIT;
66+
67+
--echo # Connection con2
68+
connection con2;
69+
--reap
70+
71+
72+
disconnect con1;
73+
disconnect con2;
74+
75+
# clear
76+
connection default;
77+
DROP TABLE test.t1;
78+
79+
--source include/wait_until_count_sessions.inc

mysql-test/t/lock_no_wait.test

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# test for lock table .. wait/no_wait
2+
3+
# Save the initial number of concurrent sessions.
4+
--source include/count_sessions.inc
5+
6+
--disable_warnings
7+
DROP TABLE IF EXISTS test.t1;
8+
CREATE TABLE test.t1 (c1 INT, c2 INT);
9+
INSERT INTO t1 (c1,c2) values (1,1),(2,2),(3,3),(4,4);
10+
--enable_warnings
11+
12+
--echo # Connection con1
13+
connect(con1,localhost,root,,);
14+
LOCK TABLE test.t1 WRITE;
15+
16+
--echo # Connection con2
17+
connect(con2,localhost,root,,);
18+
# The following statement should hang because con1 is locking the table
19+
--error ER_LOCK_WAIT_TIMEOUT
20+
LOCK TABLE test.t1 WRITE NO_WAIT;
21+
--error ER_LOCK_WAIT_TIMEOUT
22+
LOCK TABLE test.t1 WRITE WAIT 1;
23+
# wait time rang from 0 to 365*24*3600=31536000
24+
--error ER_WRONG_VALUE_FOR_VAR
25+
LOCK TABLE test.t1 WRITE WAIT 31536001;
26+
--send
27+
LOCK TABLE test.t1 WRITE WAIT 10;
28+
29+
--echo # Connection con1
30+
connection con1;
31+
UNLOCK TABLES;
32+
33+
--echo # Connection con2
34+
connection con2;
35+
--reap
36+
37+
# clear
38+
disconnect con1;
39+
disconnect con2;
40+
41+
connection default;
42+
DROP TABLE test.t1;
43+
44+
45+
--source include/wait_until_count_sessions.inc

sql/mdl.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,15 @@ MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
22112211
*/
22122212
lock= ticket->m_lock;
22132213

2214+
if (lock_wait_timeout == 0)
2215+
{
2216+
DBUG_ASSERT(mdl_request->key.ptr()[0] == MDL_key::TABLE);
2217+
mysql_prlock_unlock(&lock->m_rwlock);
2218+
MDL_ticket::destroy(ticket);
2219+
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
2220+
return TRUE;
2221+
}
2222+
22142223
lock->m_waiting.add_ticket(ticket);
22152224

22162225
/*

sql/sql_base.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4057,13 +4057,21 @@ Open_table_context::Open_table_context(THD *thd, uint flags)
40574057
:m_thd(thd),
40584058
m_failed_table(NULL),
40594059
m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()),
4060-
m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ?
4061-
LONG_TIMEOUT : thd->variables.lock_wait_timeout),
40624060
m_flags(flags),
40634061
m_action(OT_NO_ACTION),
40644062
m_has_locks(thd->mdl_context.has_locks()),
40654063
m_has_protection_against_grl(FALSE)
4066-
{}
4064+
{
4065+
if (flags & MYSQL_LOCK_IGNORE_TIMEOUT)
4066+
m_timeout= LONG_TIMEOUT;
4067+
else
4068+
{
4069+
if (thd->lex->wait_time == ULONG_MAX)
4070+
m_timeout= thd->variables.lock_wait_timeout;
4071+
else
4072+
m_timeout= thd->lex->wait_time;
4073+
}
4074+
}
40674075

40684076

40694077
/**

0 commit comments

Comments
 (0)