Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
ec762cbd
Commit
ec762cbd
authored
Apr 03, 2009
by
Davi Arnaut
Browse files
Options
Browse Files
Download
Plain Diff
Merge Bug#43230 into mysql-5.1-bugteam
parents
48f43531
aebaf079
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
236 additions
and
4 deletions
+236
-4
mysql-test/r/lock_multi.result
mysql-test/r/lock_multi.result
+55
-0
mysql-test/t/lock_multi.test
mysql-test/t/lock_multi.test
+128
-0
sql/sql_lex.cc
sql/sql_lex.cc
+1
-0
sql/sql_lex.h
sql/sql_lex.h
+16
-0
sql/sql_parse.cc
sql/sql_parse.cc
+30
-3
sql/sql_yacc.yy
sql/sql_yacc.yy
+6
-1
No files found.
mysql-test/r/lock_multi.result
View file @
ec762cbd
...
...
@@ -96,6 +96,61 @@ alter table t1 auto_increment=0;
alter table t1 auto_increment=0;
unlock tables;
drop table t1;
create table t1 (a int);
create table t2 like t1;
# con1
lock tables t1 write;
# con2
flush tables with read lock;
# con5
# global read lock is taken
# con3
select * from t2 for update;
# waiting for release of read lock
# con4
# would hang and later cause a deadlock
flush tables t2;
# clean up
unlock tables;
unlock tables;
a
drop table t1,t2;
#
# Lightweight version:
# Ensure that the wait for a GRL is done before opening tables.
#
create table t1 (a int);
create table t2 like t1;
#
# UPDATE
#
# default
flush tables with read lock;
# con1
update t2 set a = 1;
# default
# statement is waiting for release of read lock
# con2
flush table t2;
# default
unlock tables;
# con1
#
# LOCK TABLES .. WRITE
#
# default
flush tables with read lock;
# con1
lock tables t2 write;
# default
# statement is waiting for release of read lock
# con2
flush table t2;
# default
unlock tables;
# con1
unlock tables;
drop table t1,t2;
End of 5.0 tests
create table t1 (i int);
lock table t1 read;
...
...
mysql-test/t/lock_multi.test
View file @
ec762cbd
...
...
@@ -317,6 +317,134 @@ reap;
connection
locker
;
drop
table
t1
;
#
# Bug#43230: SELECT ... FOR UPDATE can hang with FLUSH TABLES WITH READ LOCK indefinitely
#
connect
(
con1
,
localhost
,
root
,,);
connect
(
con2
,
localhost
,
root
,,);
connect
(
con3
,
localhost
,
root
,,);
connect
(
con4
,
localhost
,
root
,,);
connect
(
con5
,
localhost
,
root
,,);
create
table
t1
(
a
int
);
create
table
t2
like
t1
;
connection
con1
;
--
echo
# con1
lock
tables
t1
write
;
connection
con2
;
--
echo
# con2
send
flush
tables
with
read
lock
;
connection
con5
;
--
echo
# con5
let
$show_statement
=
SHOW
PROCESSLIST
;
let
$field
=
State
;
let
$condition
=
=
'Flushing tables'
;
--
source
include
/
wait_show_condition
.
inc
--
echo
# global read lock is taken
connection
con3
;
--
echo
# con3
send
select
*
from
t2
for
update
;
connection
con5
;
let
$show_statement
=
SHOW
PROCESSLIST
;
let
$field
=
State
;
let
$condition
=
=
'Waiting for release of readlock'
;
--
source
include
/
wait_show_condition
.
inc
--
echo
# waiting for release of read lock
connection
con4
;
--
echo
# con4
--
echo
# would hang and later cause a deadlock
flush
tables
t2
;
connection
con1
;
--
echo
# clean up
unlock
tables
;
connection
con2
;
--
reap
unlock
tables
;
connection
con3
;
--
reap
connection
default
;
disconnect
con5
;
disconnect
con4
;
disconnect
con3
;
disconnect
con2
;
disconnect
con1
;
drop
table
t1
,
t2
;
--
echo
#
--
echo
# Lightweight version:
--
echo
# Ensure that the wait for a GRL is done before opening tables.
--
echo
#
connect
(
con1
,
localhost
,
root
,,);
connect
(
con2
,
localhost
,
root
,,);
create
table
t1
(
a
int
);
create
table
t2
like
t1
;
--
echo
#
--
echo
# UPDATE
--
echo
#
connection
default
;
--
echo
# default
flush
tables
with
read
lock
;
connection
con1
;
--
echo
# con1
send
update
t2
set
a
=
1
;
connection
default
;
--
echo
# default
let
$show_statement
=
SHOW
PROCESSLIST
;
let
$field
=
State
;
let
$condition
=
=
'Waiting for release of readlock'
;
--
source
include
/
wait_show_condition
.
inc
--
echo
# statement is waiting for release of read lock
connection
con2
;
--
echo
# con2
flush
table
t2
;
connection
default
;
--
echo
# default
unlock
tables
;
connection
con1
;
--
echo
# con1
--
reap
--
echo
#
--
echo
# LOCK TABLES .. WRITE
--
echo
#
connection
default
;
--
echo
# default
flush
tables
with
read
lock
;
connection
con1
;
--
echo
# con1
send
lock
tables
t2
write
;
connection
default
;
--
echo
# default
let
$show_statement
=
SHOW
PROCESSLIST
;
let
$field
=
State
;
let
$condition
=
=
'Waiting for release of readlock'
;
--
source
include
/
wait_show_condition
.
inc
--
echo
# statement is waiting for release of read lock
connection
con2
;
--
echo
# con2
flush
table
t2
;
connection
default
;
--
echo
# default
unlock
tables
;
connection
con1
;
--
echo
# con1
--
reap
unlock
tables
;
connection
default
;
disconnect
con2
;
disconnect
con1
;
drop
table
t1
,
t2
;
--
echo
End
of
5.0
tests
...
...
sql/sql_lex.cc
View file @
ec762cbd
...
...
@@ -348,6 +348,7 @@ void lex_start(THD *thd)
lex
->
nest_level
=
0
;
lex
->
allow_sum_func
=
0
;
lex
->
in_sum_func
=
NULL
;
lex
->
protect_against_global_read_lock
=
FALSE
;
/*
ok, there must be a better solution for this, long-term
I tried "bzero" in the sql_yacc.yy code, but that for
...
...
sql/sql_lex.h
View file @
ec762cbd
...
...
@@ -1745,6 +1745,22 @@ typedef struct st_lex : public Query_tables_list
bool
escape_used
;
bool
is_lex_started
;
/* If lex_start() did run. For debugging. */
/*
Special case for SELECT .. FOR UPDATE and LOCK TABLES .. WRITE.
Protect from a impending GRL as otherwise the thread might deadlock
if it starts waiting for the GRL in mysql_lock_tables.
The protection is needed because there is a race between setting
the global read lock and waiting for all open tables to be closed.
The problem is a circular wait where a thread holding "old" open
tables will wait for the global read lock to be released while the
thread holding the global read lock will wait for all "old" open
tables to be closed -- the flush part of flush tables with read
lock.
*/
bool
protect_against_global_read_lock
;
st_lex
();
virtual
~
st_lex
()
...
...
sql/sql_parse.cc
View file @
ec762cbd
...
...
@@ -2200,8 +2200,15 @@ mysql_execute_command(THD *thd)
res
=
check_access
(
thd
,
lex
->
exchange
?
SELECT_ACL
|
FILE_ACL
:
SELECT_ACL
,
any_db
,
0
,
0
,
0
,
0
);
if
(
!
res
)
res
=
execute_sqlcom_select
(
thd
,
all_tables
);
if
(
res
)
break
;
if
(
!
thd
->
locked_tables
&&
lex
->
protect_against_global_read_lock
&&
!
(
need_start_waiting
=
!
wait_if_global_read_lock
(
thd
,
0
,
1
)))
break
;
res
=
execute_sqlcom_select
(
thd
,
all_tables
);
break
;
case
SQLCOM_PREPARE
:
{
...
...
@@ -3006,6 +3013,9 @@ end_with_restore_list:
DBUG_ASSERT
(
first_table
==
all_tables
&&
first_table
!=
0
);
if
(
update_precheck
(
thd
,
all_tables
))
break
;
if
(
!
thd
->
locked_tables
&&
!
(
need_start_waiting
=
!
wait_if_global_read_lock
(
thd
,
0
,
1
)))
goto
error
;
DBUG_ASSERT
(
select_lex
->
offset_limit
==
0
);
unit
->
set_limit
(
select_lex
);
res
=
(
up_result
=
mysql_update
(
thd
,
all_tables
,
...
...
@@ -3032,6 +3042,15 @@ end_with_restore_list:
else
res
=
0
;
/*
Protection might have already been risen if its a fall through
from the SQLCOM_UPDATE case above.
*/
if
(
!
thd
->
locked_tables
&&
lex
->
sql_command
==
SQLCOM_UPDATE_MULTI
&&
!
(
need_start_waiting
=
!
wait_if_global_read_lock
(
thd
,
0
,
1
)))
goto
error
;
res
=
mysql_multi_update_prepare
(
thd
);
#ifdef HAVE_REPLICATION
...
...
@@ -3229,7 +3248,8 @@ end_with_restore_list:
ER
(
ER_LOCK_OR_ACTIVE_TRANSACTION
),
MYF
(
0
));
goto
error
;
}
if
(
!
(
need_start_waiting
=
!
wait_if_global_read_lock
(
thd
,
0
,
1
)))
goto
error
;
res
=
mysql_truncate
(
thd
,
first_table
,
0
);
break
;
case
SQLCOM_DELETE
:
...
...
@@ -3402,6 +3422,10 @@ end_with_restore_list:
if
(
check_one_table_access
(
thd
,
privilege
,
all_tables
))
goto
error
;
if
(
!
thd
->
locked_tables
&&
!
(
need_start_waiting
=
!
wait_if_global_read_lock
(
thd
,
0
,
1
)))
goto
error
;
res
=
mysql_load
(
thd
,
lex
->
exchange
,
first_table
,
lex
->
field_list
,
lex
->
update_list
,
lex
->
value_list
,
lex
->
duplicates
,
lex
->
ignore
,
(
bool
)
lex
->
local_file
);
...
...
@@ -3472,6 +3496,9 @@ end_with_restore_list:
if
(
check_table_access
(
thd
,
LOCK_TABLES_ACL
|
SELECT_ACL
,
all_tables
,
UINT_MAX
,
FALSE
))
goto
error
;
if
(
lex
->
protect_against_global_read_lock
&&
!
(
need_start_waiting
=
!
wait_if_global_read_lock
(
thd
,
0
,
1
)))
goto
error
;
thd
->
in_lock_tables
=
1
;
thd
->
options
|=
OPTION_TABLE_LOCK
;
...
...
sql/sql_yacc.yy
View file @
ec762cbd
...
...
@@ -6538,6 +6538,7 @@ select_lock_type:
lex->current_select->set_lock_for_tables(TL_WRITE);
lex->current_select->lock_option= TL_WRITE;
lex->safe_to_cache_query=0;
lex->protect_against_global_read_lock= TRUE;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
...
...
@@ -12182,8 +12183,12 @@ table_lock_list:
table_lock:
table_ident opt_table_alias lock_option
{
if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
thr_lock_type lock_type= (thr_lock_type) $3;
if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type))
MYSQL_YYABORT;
/* If table is to be write locked, protect from a impending GRL. */
if (lock_type >= TL_WRITE_ALLOW_WRITE)
Lex->protect_against_global_read_lock= TRUE;
}
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment