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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
7116431a
Commit
7116431a
authored
Mar 13, 2010
by
Konstantin Osipov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
A review comment for the fix for Bug#46672.
Remove unnecessary need_reopen loops.
parent
ea70b6a2
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
232 additions
and
372 deletions
+232
-372
mysql-test/r/mdl_sync.result
mysql-test/r/mdl_sync.result
+11
-5
mysql-test/t/mdl_sync.test
mysql-test/t/mdl_sync.test
+22
-16
sql/ha_ndbcluster_binlog.cc
sql/ha_ndbcluster_binlog.cc
+0
-2
sql/lock.cc
sql/lock.cc
+33
-103
sql/log_event_old.cc
sql/log_event_old.cc
+20
-71
sql/mysql_priv.h
sql/mysql_priv.h
+2
-4
sql/share/errmsg-utf8.txt
sql/share/errmsg-utf8.txt
+3
-0
sql/sql_base.cc
sql/sql_base.cc
+59
-62
sql/sql_class.h
sql/sql_class.h
+1
-4
sql/sql_db.cc
sql/sql_db.cc
+1
-1
sql/sql_handler.cc
sql/sql_handler.cc
+57
-3
sql/sql_insert.cc
sql/sql_insert.cc
+6
-27
sql/sql_table.cc
sql/sql_table.cc
+1
-1
sql/sql_update.cc
sql/sql_update.cc
+16
-73
No files found.
mysql-test/r/mdl_sync.result
View file @
7116431a
...
@@ -1678,14 +1678,21 @@ insert into t2 values (1);;
...
@@ -1678,14 +1678,21 @@ insert into t2 values (1);;
#
#
# Switching to connection 'handler_con1'.
# Switching to connection 'handler_con1'.
# Wait until INSERT is blocked on table-level lock.
# Wait until INSERT is blocked on table-level lock.
# The below statement should not cause deadlock.
# Sending 'alter table t1 drop column j'. It should not cause
# deadlock.
alter table t1 drop column j;
alter table t1 drop column j;
unlock tables;
# Switching to connection 'handler_con2'.
# Wait until ALTER is blocked during upgrade.
#
#
# Switching to connection 'default'.
# Switching to connection 'default'.
# Reap INSERT.
# Reap INSERT.
ERROR HY000: Wait on a lock was aborted due to a pending exclusive lock
handler t1 close;
handler t1 close;
#
#
# Switching to connection 'handler_con1'.
# Reaping 'alter table t1 drop column j'
unlock tables;
# Switching to connection 'default'.
# Then, check the scenario in which upgrade of SNRW lock to X
# Then, check the scenario in which upgrade of SNRW lock to X
# lock is blocked by HANDLER which is open in connection currently
# lock is blocked by HANDLER which is open in connection currently
# waiting to get SW lock on the same table.
# waiting to get SW lock on the same table.
...
@@ -2248,6 +2255,8 @@ SET DEBUG_SYNC= 'RESET';
...
@@ -2248,6 +2255,8 @@ SET DEBUG_SYNC= 'RESET';
# Bug#50786 Assertion `thd->mdl_context.trans_sentinel() == __null'
# Bug#50786 Assertion `thd->mdl_context.trans_sentinel() == __null'
# failed in open_ltable()
# failed in open_ltable()
#
#
# Supress warnings written to the log file
call mtr.add_suppression("Wait on a lock was aborted due to a pending exclusive lock");
DROP TABLE IF EXISTS t1, t2;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (i INT);
CREATE TABLE t1 (i INT);
CREATE TABLE t2 (i INT);
CREATE TABLE t2 (i INT);
...
@@ -2271,7 +2280,6 @@ SET DEBUG_SYNC= 'now WAIT_FOR parked';
...
@@ -2271,7 +2280,6 @@ SET DEBUG_SYNC= 'now WAIT_FOR parked';
# Sending:
# Sending:
SELECT 1;
SELECT 1;
# connection: con3
# connection: con3
# Sending:
ALTER TABLE t1 ADD COLUMN j INT;
ALTER TABLE t1 ADD COLUMN j INT;
# connection: default
# connection: default
SET DEBUG_SYNC= 'now SIGNAL go';
SET DEBUG_SYNC= 'now SIGNAL go';
...
@@ -2284,8 +2292,6 @@ HANDLER t1 CLOSE;
...
@@ -2284,8 +2292,6 @@ HANDLER t1 CLOSE;
# Reaping SELECT 1
# Reaping SELECT 1
1
1
1
1
# connection: con3
# Reaping ALTER TABLE t1 ADD COLUMN j INT
# connection: default
# connection: default
DROP TABLE t1, t2;
DROP TABLE t1, t2;
SET DEBUG_SYNC= 'RESET';
SET DEBUG_SYNC= 'RESET';
...
...
mysql-test/t/mdl_sync.test
View file @
7116431a
...
@@ -2277,17 +2277,32 @@ let $wait_condition=
...
@@ -2277,17 +2277,32 @@ let $wait_condition=
select
count
(
*
)
=
1
from
information_schema
.
processlist
select
count
(
*
)
=
1
from
information_schema
.
processlist
where
state
=
"Table lock"
and
info
=
"insert into t2 values (1)"
;
where
state
=
"Table lock"
and
info
=
"insert into t2 values (1)"
;
--
source
include
/
wait_condition
.
inc
--
source
include
/
wait_condition
.
inc
--
echo
# The below statement should not cause deadlock.
--
echo
# Sending 'alter table t1 drop column j'. It should not cause
alter
table
t1
drop
column
j
;
--
echo
# deadlock.
unlock
tables
;
send
alter
table
t1
drop
column
j
;
--
echo
# Switching to connection 'handler_con2'.
connection
handler_con2
;
--
echo
# Wait until ALTER is blocked during upgrade.
let
$wait_condition
=
select
count
(
*
)
=
1
from
information_schema
.
processlist
where
state
=
"Waiting for table"
and
info
=
"alter table t1 drop column j"
;
--
source
include
/
wait_condition
.
inc
--
echo
#
--
echo
#
--
echo
# Switching to connection 'default'.
--
echo
# Switching to connection 'default'.
connection
default
;
connection
default
;
--
echo
# Reap INSERT.
--
echo
# Reap INSERT.
--
error
ER_LOCK_ABORTED
--
reap
--
reap
handler
t1
close
;
handler
t1
close
;
--
echo
#
--
echo
#
--
echo
# Switching to connection 'handler_con1'.
connection
handler_con1
;
--
echo
# Reaping 'alter table t1 drop column j'
--
reap
unlock
tables
;
--
echo
# Switching to connection 'default'.
connection
default
;
--
echo
# Then, check the scenario in which upgrade of SNRW lock to X
--
echo
# Then, check the scenario in which upgrade of SNRW lock to X
--
echo
# lock is blocked by HANDLER which is open in connection currently
--
echo
# lock is blocked by HANDLER which is open in connection currently
--
echo
# waiting to get SW lock on the same table.
--
echo
# waiting to get SW lock on the same table.
...
@@ -3220,6 +3235,8 @@ disconnect con2;
...
@@ -3220,6 +3235,8 @@ disconnect con2;
--
echo
# failed in open_ltable()
--
echo
# failed in open_ltable()
--
echo
#
--
echo
#
--
echo
# Supress warnings written to the log file
call
mtr
.
add_suppression
(
"Wait on a lock was aborted due to a pending exclusive lock"
);
--
disable_warnings
--
disable_warnings
DROP
TABLE
IF
EXISTS
t1
,
t2
;
DROP
TABLE
IF
EXISTS
t1
,
t2
;
--
enable_warnings
--
enable_warnings
...
@@ -3279,16 +3296,10 @@ let $wait_condition=
...
@@ -3279,16 +3296,10 @@ let $wait_condition=
# since the latter waits on a table-level lock while having a HANDLER
# since the latter waits on a table-level lock while having a HANDLER
# open. This will cause mysql_lock_tables() in con1 fail which before
# open. This will cause mysql_lock_tables() in con1 fail which before
# triggered the assert.
# triggered the assert.
--
echo
# Sending:
ALTER
TABLE
t1
ADD
COLUMN
j
INT
;
--
send
ALTER
TABLE
t1
ADD
COLUMN
j
INT
--
echo
# connection: default
--
echo
# connection: default
connection
default
;
connection
default
;
let
$wait_condition
=
SELECT
COUNT
(
*
)
=
1
FROM
information_schema
.
processlist
WHERE
state
=
"Waiting for table"
AND
info
=
"ALTER TABLE t1 ADD COLUMN j INT"
;
--
source
include
/
wait_condition
.
inc
SET
DEBUG_SYNC
=
'now SIGNAL go'
;
SET
DEBUG_SYNC
=
'now SIGNAL go'
;
--
echo
# connection: con1
--
echo
# connection: con1
...
@@ -3302,11 +3313,6 @@ connection con2;
...
@@ -3302,11 +3313,6 @@ connection con2;
--
echo
# Reaping SELECT 1
--
echo
# Reaping SELECT 1
--
reap
--
reap
--
echo
# connection: con3
connection
con3
;
--
echo
# Reaping ALTER TABLE t1 ADD COLUMN j INT
--
reap
--
echo
# connection: default
--
echo
# connection: default
connection
default
;
connection
default
;
DROP
TABLE
t1
,
t2
;
DROP
TABLE
t1
,
t2
;
...
...
sql/ha_ndbcluster_binlog.cc
View file @
7116431a
...
@@ -2346,7 +2346,6 @@ static int open_ndb_binlog_index(THD *thd, TABLE **ndb_binlog_index)
...
@@ -2346,7 +2346,6 @@ static int open_ndb_binlog_index(THD *thd, TABLE **ndb_binlog_index)
thd
->
proc_info
=
"Opening "
NDB_REP_DB
"."
NDB_REP_TABLE
;
thd
->
proc_info
=
"Opening "
NDB_REP_DB
"."
NDB_REP_TABLE
;
tables
->
required_type
=
FRMTYPE_TABLE
;
tables
->
required_type
=
FRMTYPE_TABLE
;
uint
counter
;
thd
->
clear_error
();
thd
->
clear_error
();
if
(
open_and_lock_tables
(
thd
,
tables
,
FALSE
,
0
))
if
(
open_and_lock_tables
(
thd
,
tables
,
FALSE
,
0
))
{
{
...
@@ -2374,7 +2373,6 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
...
@@ -2374,7 +2373,6 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
{
{
ndb_binlog_index_row
&
row
=
*
(
ndb_binlog_index_row
*
)
_row
;
ndb_binlog_index_row
&
row
=
*
(
ndb_binlog_index_row
*
)
_row
;
int
error
=
0
;
int
error
=
0
;
bool
need_reopen
;
/*
/*
Turn of binlogging to prevent the table changes to be written to
Turn of binlogging to prevent the table changes to be written to
the binary log.
the binary log.
...
...
sql/lock.cc
View file @
7116431a
...
@@ -97,7 +97,7 @@ static void print_lock_error(int error, const char *);
...
@@ -97,7 +97,7 @@ static void print_lock_error(int error, const char *);
/* Map the return value of thr_lock to an error from errmsg.txt */
/* Map the return value of thr_lock to an error from errmsg.txt */
static
int
thr_lock_errno_to_mysql
[]
=
static
int
thr_lock_errno_to_mysql
[]
=
{
0
,
1
,
ER_LOCK_WAIT_TIMEOUT
,
ER_LOCK_DEADLOCK
};
{
0
,
ER_LOCK_ABORTED
,
ER_LOCK_WAIT_TIMEOUT
,
ER_LOCK_DEADLOCK
};
/**
/**
Perform semantic checks for mysql_lock_tables.
Perform semantic checks for mysql_lock_tables.
...
@@ -108,8 +108,7 @@ static int thr_lock_errno_to_mysql[]=
...
@@ -108,8 +108,7 @@ static int thr_lock_errno_to_mysql[]=
@return 0 if all the check passed, non zero if a check failed.
@return 0 if all the check passed, non zero if a check failed.
*/
*/
static
int
static
int
lock_tables_check
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
lock_tables_check
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
)
bool
*
write_lock_used
,
uint
flags
)
{
{
uint
system_count
,
i
;
uint
system_count
,
i
;
bool
is_superuser
,
log_table_write_query
;
bool
is_superuser
,
log_table_write_query
;
...
@@ -117,7 +116,6 @@ lock_tables_check(THD *thd, TABLE **tables, uint count,
...
@@ -117,7 +116,6 @@ lock_tables_check(THD *thd, TABLE **tables, uint count,
DBUG_ENTER
(
"lock_tables_check"
);
DBUG_ENTER
(
"lock_tables_check"
);
system_count
=
0
;
system_count
=
0
;
*
write_lock_used
=
FALSE
;
is_superuser
=
thd
->
security_ctx
->
master_access
&
SUPER_ACL
;
is_superuser
=
thd
->
security_ctx
->
master_access
&
SUPER_ACL
;
log_table_write_query
=
(
is_log_table_write_query
(
thd
->
lex
->
sql_command
)
log_table_write_query
=
(
is_log_table_write_query
(
thd
->
lex
->
sql_command
)
||
((
flags
&
MYSQL_LOCK_PERF_SCHEMA
)
!=
0
));
||
((
flags
&
MYSQL_LOCK_PERF_SCHEMA
)
!=
0
));
...
@@ -153,8 +151,6 @@ lock_tables_check(THD *thd, TABLE **tables, uint count,
...
@@ -153,8 +151,6 @@ lock_tables_check(THD *thd, TABLE **tables, uint count,
if
(
t
->
reginfo
.
lock_type
>=
TL_WRITE_ALLOW_WRITE
)
if
(
t
->
reginfo
.
lock_type
>=
TL_WRITE_ALLOW_WRITE
)
{
{
*
write_lock_used
=
TRUE
;
if
(
t
->
s
->
table_category
==
TABLE_CATEGORY_SYSTEM
)
if
(
t
->
s
->
table_category
==
TABLE_CATEGORY_SYSTEM
)
system_count
++
;
system_count
++
;
...
@@ -273,12 +269,8 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
...
@@ -273,12 +269,8 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
@param tables An array of pointers to the tables to lock.
@param tables An array of pointers to the tables to lock.
@param count The number of tables to lock.
@param count The number of tables to lock.
@param flags Options:
@param flags Options:
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value.
MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value.
@param need_reopen Out parameter, TRUE if some tables were altered
or deleted and should be reopened by caller.
@note Caller of this function should always be ready to handle request to
@note Caller of this function should always be ready to handle request to
reopen table unless there are external invariants which guarantee
reopen table unless there are external invariants which guarantee
...
@@ -289,125 +281,63 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
...
@@ -289,125 +281,63 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
@retval NULL on error or if some tables should be reopen.
@retval NULL on error or if some tables should be reopen.
*/
*/
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
)
uint
flags
,
bool
*
need_reopen
)
{
{
int
rc
;
int
rc
;
MYSQL_LOCK
*
sql_lock
;
MYSQL_LOCK
*
sql_lock
;
bool
write_lock_used
;
DBUG_ENTER
(
"mysql_lock_tables"
);
DBUG_ENTER
(
"mysql_lock_tables"
);
*
need_reopen
=
FALSE
;
if
(
lock_tables_check
(
thd
,
tables
,
count
,
flags
))
if
(
lock_tables_check
(
thd
,
tables
,
count
,
&
write_lock_used
,
flags
))
DBUG_RETURN
(
NULL
);
DBUG_RETURN
(
NULL
);
ulong
timeout
=
(
flags
&
MYSQL_LOCK_IGNORE_TIMEOUT
)
?
ulong
timeout
=
(
flags
&
MYSQL_LOCK_IGNORE_TIMEOUT
)
?
LONG_TIMEOUT
:
thd
->
variables
.
lock_wait_timeout
;
LONG_TIMEOUT
:
thd
->
variables
.
lock_wait_timeout
;
for
(;;)
if
(
!
(
sql_lock
=
get_lock_data
(
thd
,
tables
,
count
,
GET_LOCK_STORE_LOCKS
)))
{
DBUG_RETURN
(
NULL
);
if
(
!
(
sql_lock
=
get_lock_data
(
thd
,
tables
,
count
,
GET_LOCK_STORE_LOCKS
)))
break
;
if
(
global_read_lock
&&
write_lock_used
&&
!
(
flags
&
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
))
{
/*
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
Wait until the lock is gone
*/
if
(
thd
->
global_read_lock
.
wait_if_global_read_lock
(
thd
,
1
,
1
))
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data_and_free
(
&
sql_lock
);
break
;
}
if
(
thd
->
version
!=
refresh_version
)
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data_and_free
(
&
sql_lock
);
goto
retry
;
}
}
thd_proc_info
(
thd
,
"System lock"
);
DBUG_PRINT
(
"info"
,
(
"thd->proc_info %s"
,
thd
->
proc_info
));
if
(
sql_lock
->
table_count
&&
lock_external
(
thd
,
sql_lock
->
table
,
sql_lock
->
table_count
))
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data_and_free
(
&
sql_lock
);
break
;
}
DBUG_PRINT
(
"info"
,
(
"thd->proc_info %s"
,
thd
->
proc_info
));
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
memcpy
(
sql_lock
->
locks
+
sql_lock
->
lock_count
,
sql_lock
->
locks
,
sql_lock
->
lock_count
*
sizeof
(
*
sql_lock
->
locks
));
/* Lock on the copied half of the lock data array. */
rc
=
thr_lock_errno_to_mysql
[(
int
)
thr_multi_lock
(
sql_lock
->
locks
+
sql_lock
->
lock_count
,
sql_lock
->
lock_count
,
thd
->
lock_id
,
timeout
)];
if
(
rc
>
1
)
/* a timeout or a deadlock */
{
if
(
sql_lock
->
table_count
)
(
void
)
unlock_external
(
thd
,
sql_lock
->
table
,
sql_lock
->
table_count
);
reset_lock_data_and_free
(
&
sql_lock
);
my_error
(
rc
,
MYF
(
0
));
break
;
}
else
if
(
rc
==
1
)
/* aborted or killed */
{
/*
reset_lock_data is required here. If thr_multi_lock fails it
resets lock type for tables, which were locked before (and
including) one that caused error. Lock type for other tables
preserved.
*/
reset_lock_data
(
sql_lock
);
sql_lock
->
lock_count
=
0
;
// Locks are already freed
// Fall through: unlock, reset lock data, free and retry
}
else
{
/* Success */
break
;
}
thd_proc_info
(
thd
,
0
);
/* going to retry, unlock all tables */
if
(
sql_lock
->
lock_count
)
thr_multi_unlock
(
sql_lock
->
locks
,
sql_lock
->
lock_count
);
thd_proc_info
(
thd
,
"System lock"
);
DBUG_PRINT
(
"info"
,
(
"thd->proc_info %s"
,
thd
->
proc_info
));
if
(
sql_lock
->
table_count
&&
lock_external
(
thd
,
sql_lock
->
table
,
sql_lock
->
table_count
))
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data_and_free
(
&
sql_lock
);
goto
end
;
}
DBUG_PRINT
(
"info"
,
(
"thd->proc_info %s"
,
thd
->
proc_info
));
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
memcpy
(
sql_lock
->
locks
+
sql_lock
->
lock_count
,
sql_lock
->
locks
,
sql_lock
->
lock_count
*
sizeof
(
*
sql_lock
->
locks
));
/* Lock on the copied half of the lock data array. */
rc
=
thr_lock_errno_to_mysql
[(
int
)
thr_multi_lock
(
sql_lock
->
locks
+
sql_lock
->
lock_count
,
sql_lock
->
lock_count
,
thd
->
lock_id
,
timeout
)];
if
(
rc
)
{
if
(
sql_lock
->
table_count
)
if
(
sql_lock
->
table_count
)
(
void
)
unlock_external
(
thd
,
sql_lock
->
table
,
sql_lock
->
table_count
);
(
void
)
unlock_external
(
thd
,
sql_lock
->
table
,
sql_lock
->
table_count
);
/*
If thr_multi_lock fails it resets lock type for tables, which
were locked before (and including) one that caused error. Lock
type for other tables preserved.
*/
reset_lock_data_and_free
(
&
sql_lock
);
reset_lock_data_and_free
(
&
sql_lock
);
retry:
if
(
!
thd
->
killed
)
/* Let upper level close all used tables and retry or give error. */
my_error
(
rc
,
MYF
(
0
));
*
need_reopen
=
TRUE
;
break
;
}
}
end:
thd_proc_info
(
thd
,
0
);
thd_proc_info
(
thd
,
0
);
if
(
thd
->
killed
)
if
(
thd
->
killed
)
{
{
thd
->
send_kill_message
();
thd
->
send_kill_message
();
if
(
sql_lock
)
if
(
sql_lock
)
{
{
mysql_unlock_tables
(
thd
,
sql_lock
);
mysql_unlock_tables
(
thd
,
sql_lock
);
sql_lock
=
0
;
sql_lock
=
0
;
}
}
}
}
thd
->
set_time_after_lock
();
thd
->
set_time_after_lock
();
DBUG_RETURN
(
sql_lock
);
DBUG_RETURN
(
sql_lock
);
}
}
...
...
sql/log_event_old.cc
View file @
7116431a
...
@@ -1455,8 +1455,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
...
@@ -1455,8 +1455,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
*/
if
(
!
thd
->
lock
)
if
(
!
thd
->
lock
)
{
{
bool
need_reopen
=
1
;
/* To execute the first lap of the loop below */
/*
/*
lock_tables() reads the contents of thd->lex, so they must be
lock_tables() reads the contents of thd->lex, so they must be
initialized. Contrary to in
initialized. Contrary to in
...
@@ -1465,80 +1463,31 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
...
@@ -1465,80 +1463,31 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
*/
lex_start
(
thd
);
lex_start
(
thd
);
while
((
error
=
lock_tables
(
thd
,
rli
->
tables_to_lock
,
if
((
error
=
lock_tables
(
thd
,
rli
->
tables_to_lock
,
rli
->
tables_to_lock_count
,
0
,
rli
->
tables_to_lock_count
,
0
)))
&
need_reopen
)))
{
{
if
(
!
need_reopen
)
if
(
thd
->
is_slave_error
||
thd
->
is_fatal_error
)
{
if
(
thd
->
is_slave_error
||
thd
->
is_fatal_error
)
{
/*
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
uint
actual_error
=
thd
->
net
.
last_errno
;
rli
->
report
(
ERROR_LEVEL
,
actual_error
,
"Error '%s' in %s event: when locking tables"
,
(
actual_error
?
thd
->
net
.
last_error
:
"unexpected success or fatal error"
),
get_type_str
());
thd
->
is_fatal_error
=
1
;
}
else
{
rli
->
report
(
ERROR_LEVEL
,
error
,
"Error in %s event: when locking tables"
,
get_type_str
());
}
const_cast
<
Relay_log_info
*>
(
rli
)
->
slave_close_thread_tables
(
thd
);
DBUG_RETURN
(
error
);
}
/*
So we need to reopen the tables.
We need to flush the pending RBR event, since it keeps a
pointer to an open table.
ALTERNATIVE SOLUTION (not implemented): Extract a pointer to
the pending RBR event and reset the table pointer after the
tables has been reopened.
NOTE: For this new scheme there should be no pending event:
need to add code to assert that is the case.
*/
error
=
thd
->
binlog_flush_pending_rows_event
(
FALSE
);
if
(
error
)
{
{
rli
->
report
(
ERROR_LEVEL
,
ER_SLAVE_FATAL_ERROR
,
/*
ER
(
ER_SLAVE_FATAL_ERROR
),
Error reporting borrowed from Query_log_event with many excessive
"call to binlog_flush_pending_rows_event() failed"
);
simplifications (we don't honour --slave-skip-errors)
thd
->
is_slave_error
=
1
;
*/
DBUG_RETURN
(
error
);
uint
actual_error
=
thd
->
net
.
last_errno
;
rli
->
report
(
ERROR_LEVEL
,
actual_error
,
"Error '%s' in %s event: when locking tables"
,
(
actual_error
?
thd
->
net
.
last_error
:
"unexpected success or fatal error"
),
get_type_str
());
thd
->
is_fatal_error
=
1
;
}
}
TABLE_LIST
*
tables
=
rli
->
tables_to_lock
;
else
close_tables_for_reopen
(
thd
,
&
tables
,
NULL
);
uint
tables_count
=
rli
->
tables_to_lock_count
;
if
((
error
=
open_tables
(
thd
,
&
tables
,
&
tables_count
,
0
)))
{
{
if
(
thd
->
is_slave_error
||
thd
->
is_fatal_error
)
rli
->
report
(
ERROR_LEVEL
,
error
,
{
"Error in %s event: when locking tables"
,
/*
get_type_str
());
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
uint
actual_error
=
thd
->
net
.
last_errno
;
rli
->
report
(
ERROR_LEVEL
,
actual_error
,
"Error '%s' on reopening tables"
,
(
actual_error
?
thd
->
net
.
last_error
:
"unexpected success or fatal error"
));
thd
->
is_slave_error
=
1
;
}
const_cast
<
Relay_log_info
*>
(
rli
)
->
slave_close_thread_tables
(
thd
);
DBUG_RETURN
(
error
);
}
}
const_cast
<
Relay_log_info
*>
(
rli
)
->
slave_close_thread_tables
(
thd
);
DBUG_RETURN
(
error
);
}
}
/*
/*
...
...
sql/mysql_priv.h
View file @
7116431a
...
@@ -1590,8 +1590,7 @@ inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
...
@@ -1590,8 +1590,7 @@ inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
TABLE
*
open_n_lock_single_table
(
THD
*
thd
,
TABLE_LIST
*
table_l
,
TABLE
*
open_n_lock_single_table
(
THD
*
thd
,
TABLE_LIST
*
table_l
,
thr_lock_type
lock_type
,
uint
flags
);
thr_lock_type
lock_type
,
uint
flags
);
bool
open_normal_and_derived_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
flags
);
bool
open_normal_and_derived_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
flags
);
bool
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
counter
,
uint
flags
,
bool
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
counter
,
uint
flags
);
bool
*
need_reopen
);
TABLE
*
open_temporary_table
(
THD
*
thd
,
const
char
*
path
,
const
char
*
db
,
TABLE
*
open_temporary_table
(
THD
*
thd
,
const
char
*
path
,
const
char
*
db
,
const
char
*
table_name
,
bool
link_in_list
);
const
char
*
table_name
,
bool
link_in_list
);
bool
rm_temporary_table
(
handlerton
*
base
,
char
*
path
);
bool
rm_temporary_table
(
handlerton
*
base
,
char
*
path
);
...
@@ -2145,8 +2144,7 @@ extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
...
@@ -2145,8 +2144,7 @@ extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
extern
struct
st_VioSSLFd
*
ssl_acceptor_fd
;
extern
struct
st_VioSSLFd
*
ssl_acceptor_fd
;
#endif
/* HAVE_OPENSSL */
#endif
/* HAVE_OPENSSL */
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
uint
flags
);
uint
flags
,
bool
*
need_reopen
);
/* mysql_lock_tables() and open_table() flags bits */
/* mysql_lock_tables() and open_table() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
...
...
sql/share/errmsg-utf8.txt
View file @
7116431a
...
@@ -6321,3 +6321,6 @@ ER_SPATIAL_MUST_HAVE_GEOM_COL 42000
...
@@ -6321,3 +6321,6 @@ ER_SPATIAL_MUST_HAVE_GEOM_COL 42000
ER_TOO_LONG_INDEX_COMMENT
ER_TOO_LONG_INDEX_COMMENT
eng "Comment for index '%-.64s' is too long (max = %lu)"
eng "Comment for index '%-.64s' is too long (max = %lu)"
ER_LOCK_ABORTED
eng "Wait on a lock was aborted due to a pending exclusive lock"
sql/sql_base.cc
View file @
7116431a
...
@@ -2479,6 +2479,31 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
...
@@ -2479,6 +2479,31 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
key_length
=
(
create_table_def_key
(
thd
,
key
,
table_list
,
1
)
-
key_length
=
(
create_table_def_key
(
thd
,
key
,
table_list
,
1
)
-
TMP_TABLE_KEY_EXTRA
);
TMP_TABLE_KEY_EXTRA
);
/*
We need this to work for all tables, including temporary tables,
for backwards compatibility. But not under LOCK TABLES,
since under LOCK TABLES one can't use a non-prelocked table.
This works for DO/SELECT f1() statements.
@todo: what about tmp tables used under LOCK TABLES? We used to
allow them if mysql_lock_tables() IS NOT called for them?
*/
if
(
global_read_lock
&&
table_list
->
lock_type
>=
TL_WRITE_ALLOW_WRITE
&&
!
(
flags
&
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
)
&&
!
thd
->
locked_tables_mode
)
{
/*
Someone has issued FLUSH TABLES WITH READ LOCK and we want
a write lock. Wait until the lock is gone.
*/
if
(
thd
->
global_read_lock
.
wait_if_global_read_lock
(
thd
,
1
,
1
))
DBUG_RETURN
(
TRUE
);
if
(
thd
->
version
!=
refresh_version
)
{
(
void
)
ot_ctx
->
request_backoff_action
(
Open_table_context
::
OT_WAIT_TDC
);
DBUG_RETURN
(
TRUE
);
}
}
/*
/*
Unless requested otherwise, try to resolve this table in the list
Unless requested otherwise, try to resolve this table in the list
of temporary tables of this thread. In MySQL temporary tables
of temporary tables of this thread. In MySQL temporary tables
...
@@ -3293,7 +3318,6 @@ bool
...
@@ -3293,7 +3318,6 @@ bool
Locked_tables_list
::
reopen_tables
(
THD
*
thd
)
Locked_tables_list
::
reopen_tables
(
THD
*
thd
)
{
{
Open_table_context
ot_ctx_unused
(
thd
,
LONG_TIMEOUT
);
Open_table_context
ot_ctx_unused
(
thd
,
LONG_TIMEOUT
);
bool
lt_refresh_unused
;
size_t
reopen_count
=
0
;
size_t
reopen_count
=
0
;
MYSQL_LOCK
*
lock
;
MYSQL_LOCK
*
lock
;
MYSQL_LOCK
*
merged_lock
;
MYSQL_LOCK
*
merged_lock
;
...
@@ -3333,7 +3357,7 @@ Locked_tables_list::reopen_tables(THD *thd)
...
@@ -3333,7 +3357,7 @@ Locked_tables_list::reopen_tables(THD *thd)
break something else.
break something else.
*/
*/
lock
=
mysql_lock_tables
(
thd
,
m_reopen_array
,
reopen_count
,
lock
=
mysql_lock_tables
(
thd
,
m_reopen_array
,
reopen_count
,
MYSQL_OPEN_REOPEN
,
&
lt_refresh_unused
);
MYSQL_OPEN_REOPEN
);
thd
->
in_lock_tables
=
0
;
thd
->
in_lock_tables
=
0
;
if
(
lock
==
NULL
||
(
merged_lock
=
if
(
lock
==
NULL
||
(
merged_lock
=
mysql_lock_merge
(
thd
->
lock
,
lock
))
==
NULL
)
mysql_lock_merge
(
thd
->
lock
,
lock
))
==
NULL
)
...
@@ -5061,7 +5085,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
...
@@ -5061,7 +5085,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
TABLE
*
table
;
TABLE
*
table
;
Open_table_context
ot_ctx
(
thd
,
(
lock_flags
&
MYSQL_LOCK_IGNORE_TIMEOUT
)
?
Open_table_context
ot_ctx
(
thd
,
(
lock_flags
&
MYSQL_LOCK_IGNORE_TIMEOUT
)
?
LONG_TIMEOUT
:
thd
->
variables
.
lock_wait_timeout
);
LONG_TIMEOUT
:
thd
->
variables
.
lock_wait_timeout
);
bool
refresh
;
bool
error
;
bool
error
;
DBUG_ENTER
(
"open_ltable"
);
DBUG_ENTER
(
"open_ltable"
);
...
@@ -5073,8 +5096,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
...
@@ -5073,8 +5096,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
/* open_ltable can be used only for BASIC TABLEs */
/* open_ltable can be used only for BASIC TABLEs */
table_list
->
required_type
=
FRMTYPE_TABLE
;
table_list
->
required_type
=
FRMTYPE_TABLE
;
retry:
while
((
error
=
open_table
(
thd
,
table_list
,
thd
->
mem_root
,
&
ot_ctx
,
lock_flags
))
&&
while
((
error
=
open_table
(
thd
,
table_list
,
thd
->
mem_root
,
&
ot_ctx
,
0
))
&&
ot_ctx
.
can_recover_from_failed_open
())
ot_ctx
.
can_recover_from_failed_open
())
{
{
/*
/*
...
@@ -5120,18 +5142,9 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
...
@@ -5120,18 +5142,9 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
DBUG_ASSERT
(
thd
->
lock
==
0
);
// You must lock everything at once
DBUG_ASSERT
(
thd
->
lock
==
0
);
// You must lock everything at once
if
((
table
->
reginfo
.
lock_type
=
lock_type
)
!=
TL_UNLOCK
)
if
((
table
->
reginfo
.
lock_type
=
lock_type
)
!=
TL_UNLOCK
)
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table_list
->
table
,
1
,
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table_list
->
table
,
1
,
lock_flags
,
&
refresh
)))
lock_flags
)))
{
{
if
(
refresh
)
table
=
0
;
{
close_thread_tables
(
thd
);
table_list
->
table
=
NULL
;
table_list
->
mdl_request
.
ticket
=
NULL
;
thd
->
mdl_context
.
rollback_to_savepoint
(
ot_ctx
.
start_of_statement_svp
());
goto
retry
;
}
else
table
=
0
;
}
}
}
}
}
}
...
@@ -5168,7 +5181,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
...
@@ -5168,7 +5181,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
Prelocking_strategy
*
prelocking_strategy
)
Prelocking_strategy
*
prelocking_strategy
)
{
{
uint
counter
;
uint
counter
;
bool
need_reopen
;
/*
/*
Remember the set of metadata locks which this connection
Remember the set of metadata locks which this connection
managed to acquire before the start of the current statement.
managed to acquire before the start of the current statement.
...
@@ -5182,28 +5194,24 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
...
@@ -5182,28 +5194,24 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
DBUG_ENTER
(
"open_and_lock_tables"
);
DBUG_ENTER
(
"open_and_lock_tables"
);
DBUG_PRINT
(
"enter"
,
(
"derived handling: %d"
,
derived
));
DBUG_PRINT
(
"enter"
,
(
"derived handling: %d"
,
derived
));
for
(
;
;
)
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
flags
,
prelocking_strategy
))
{
DBUG_RETURN
(
TRUE
);
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
flags
,
prelocking_strategy
))
DBUG_RETURN
(
TRUE
);
DBUG_EXECUTE_IF
(
"sleep_open_and_lock_after_open"
,
{
DBUG_EXECUTE_IF
(
"sleep_open_and_lock_after_open"
,
{
const
char
*
old_proc_info
=
thd
->
proc_info
;
const
char
*
old_proc_info
=
thd
->
proc_info
;
thd
->
proc_info
=
"DBUG sleep"
;
thd
->
proc_info
=
"DBUG sleep"
;
my_sleep
(
6000000
);
my_sleep
(
6000000
);
thd
->
proc_info
=
old_proc_info
;});
thd
->
proc_info
=
old_proc_info
;});
if
(
lock_tables
(
thd
,
tables
,
counter
,
flags
))
if
(
!
lock_tables
(
thd
,
tables
,
counter
,
flags
,
DBUG_RETURN
(
TRUE
);
&
need_reopen
))
break
;
if
(
!
need_reopen
)
DBUG_RETURN
(
TRUE
);
close_tables_for_reopen
(
thd
,
&
tables
,
start_of_statement_svp
);
}
if
(
derived
&&
if
(
derived
&&
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
thd
->
fill_derived_tables
()
&&
(
thd
->
fill_derived_tables
()
&&
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_filling
))))
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_filling
))))
DBUG_RETURN
(
TRUE
);
/* purecov: inspected */
DBUG_RETURN
(
TRUE
);
/* purecov: inspected */
DBUG_RETURN
(
FALSE
);
DBUG_RETURN
(
FALSE
);
}
}
...
@@ -5261,37 +5269,28 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
...
@@ -5261,37 +5269,28 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
}
}
/*
/*
*
Lock all tables in
list
Lock all tables in
a list.
SYNOPSIS
@param thd Thread handler
lock_tables()
@param tables Tables to lock
thd Thread handler
@param count Number of opened tables
tables Tables to lock
@param flags Options (see mysql_lock_tables() for details)
count Number of opened tables
flags Options (see mysql_lock_tables() for details)
need_reopen Out parameter which if TRUE indicates that some
tables were dropped or altered during this call
and therefore invoker should reopen tables and
try to lock them once again (in this case
lock_tables() will also return error).
NOTES
You can't call lock_tables() while holding thr_lock locks, as
You can't call lock_tables twice, as this would break the dead-lock-free
this would break the dead-lock-free handling thr_lock gives us.
handling thr_lock gives us. You most always get all needed locks at
You most always get all needed locks at once.
once.
If query for which we are calling this function marked as requiring
If the query for which we are calling this function is marked as
prelocking, this function will change locked_tables_mode to
requiring prelocking, this function will change
LTM_PRELOCKED.
locked_tables_mode to
LTM_PRELOCKED.
RETURN VALUES
@retval FALSE Success.
0 ok
@retval TRUE A lock wait timeout, deadlock or out of memory.
-1 Error
*/
*/
bool
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
count
,
bool
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
count
,
uint
flags
,
bool
*
need_reopen
)
uint
flags
)
{
{
TABLE_LIST
*
table
;
TABLE_LIST
*
table
;
...
@@ -5302,7 +5301,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
...
@@ -5302,7 +5301,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
*/
*/
DBUG_ASSERT
(
thd
->
locked_tables_mode
<=
LTM_LOCK_TABLES
||
DBUG_ASSERT
(
thd
->
locked_tables_mode
<=
LTM_LOCK_TABLES
||
!
thd
->
lex
->
requires_prelocking
());
!
thd
->
lex
->
requires_prelocking
());
*
need_reopen
=
FALSE
;
if
(
!
tables
&&
!
thd
->
lex
->
requires_prelocking
())
if
(
!
tables
&&
!
thd
->
lex
->
requires_prelocking
())
DBUG_RETURN
(
thd
->
decide_logging_format
(
tables
));
DBUG_RETURN
(
thd
->
decide_logging_format
(
tables
));
...
@@ -5347,7 +5345,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
...
@@ -5347,7 +5345,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
DEBUG_SYNC
(
thd
,
"before_lock_tables_takes_lock"
);
DEBUG_SYNC
(
thd
,
"before_lock_tables_takes_lock"
);
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
(
uint
)
(
ptr
-
start
),
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
(
uint
)
(
ptr
-
start
),
flags
,
need_reopen
)))
flags
)))
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
DEBUG_SYNC
(
thd
,
"after_lock_tables_takes_lock"
);
DEBUG_SYNC
(
thd
,
"after_lock_tables_takes_lock"
);
...
@@ -8989,8 +8987,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
...
@@ -8989,8 +8987,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
open tables cannot be accepted when restoring the open tables
open tables cannot be accepted when restoring the open tables
state.
state.
*/
*/
if
(
thd
->
killed
)
close_thread_tables
(
thd
);
close_thread_tables
(
thd
);
thd
->
restore_backup_open_tables_state
(
backup
);
thd
->
restore_backup_open_tables_state
(
backup
);
}
}
...
...
sql/sql_class.h
View file @
7116431a
...
@@ -1161,9 +1161,7 @@ class Dummy_error_handler : public Internal_error_handler
...
@@ -1161,9 +1161,7 @@ class Dummy_error_handler : public Internal_error_handler
class
Drop_table_error_handler
:
public
Internal_error_handler
class
Drop_table_error_handler
:
public
Internal_error_handler
{
{
public:
public:
Drop_table_error_handler
(
Internal_error_handler
*
err_handler
)
Drop_table_error_handler
()
{}
:
m_err_handler
(
err_handler
)
{
}
public:
public:
bool
handle_condition
(
THD
*
thd
,
bool
handle_condition
(
THD
*
thd
,
...
@@ -1174,7 +1172,6 @@ class Drop_table_error_handler : public Internal_error_handler
...
@@ -1174,7 +1172,6 @@ class Drop_table_error_handler : public Internal_error_handler
MYSQL_ERROR
**
cond_hdl
);
MYSQL_ERROR
**
cond_hdl
);
private:
private:
Internal_error_handler
*
m_err_handler
;
};
};
...
...
sql/sql_db.cc
View file @
7116431a
...
@@ -934,7 +934,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
...
@@ -934,7 +934,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
}
else
else
{
{
Drop_table_error_handler
err_handler
(
thd
->
get_internal_handler
())
;
Drop_table_error_handler
err_handler
;
thd
->
push_internal_handler
(
&
err_handler
);
thd
->
push_internal_handler
(
&
err_handler
);
error
=
-
1
;
error
=
-
1
;
...
...
sql/sql_handler.cc
View file @
7116431a
...
@@ -405,6 +405,56 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
...
@@ -405,6 +405,56 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
}
}
/**
A helper class to process an error from mysql_lock_tables().
HANDLER READ statement's attempt to lock the subject table
may get aborted if there is a pending DDL. In that case
we close the table, reopen it, and try to read again.
This is implicit and obscure, since HANDLER position
is lost in the process, but it's the legacy server
behaviour we should preserve.
*/
class
Sql_handler_lock_error_handler
:
public
Internal_error_handler
{
public:
virtual
bool
handle_condition
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
sqlstate
,
MYSQL_ERROR
::
enum_warning_level
level
,
const
char
*
msg
,
MYSQL_ERROR
**
cond_hdl
);
bool
need_reopen
()
const
{
return
m_need_reopen
;
};
void
init
()
{
m_need_reopen
=
FALSE
;
};
private:
bool
m_need_reopen
;
};
/**
Handle an error from mysql_lock_tables().
Ignore ER_LOCK_ABORTED errors.
*/
bool
Sql_handler_lock_error_handler
::
handle_condition
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
sqlstate
,
MYSQL_ERROR
::
enum_warning_level
level
,
const
char
*
msg
,
MYSQL_ERROR
**
cond_hdl
)
{
*
cond_hdl
=
NULL
;
if
(
sql_errno
==
ER_LOCK_ABORTED
)
m_need_reopen
=
TRUE
;
return
m_need_reopen
;
}
/*
/*
Read from a HANDLER table.
Read from a HANDLER table.
...
@@ -442,7 +492,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
...
@@ -442,7 +492,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint
num_rows
;
uint
num_rows
;
uchar
*
UNINIT_VAR
(
key
);
uchar
*
UNINIT_VAR
(
key
);
uint
UNINIT_VAR
(
key_len
);
uint
UNINIT_VAR
(
key_len
);
bool
need_reopen
;
Sql_handler_lock_error_handler
sql_handler_lock_error
;
DBUG_ENTER
(
"mysql_ha_read"
);
DBUG_ENTER
(
"mysql_ha_read"
);
DBUG_PRINT
(
"enter"
,(
"'%s'.'%s' as '%s'"
,
DBUG_PRINT
(
"enter"
,(
"'%s'.'%s' as '%s'"
,
tables
->
db
,
tables
->
table_name
,
tables
->
alias
));
tables
->
db
,
tables
->
table_name
,
tables
->
alias
));
...
@@ -506,8 +556,12 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
...
@@ -506,8 +556,12 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
thd
->
open_tables
=
hash_tables
->
table
;
thd
->
open_tables
=
hash_tables
->
table
;
lock
=
mysql_lock_tables
(
thd
,
&
thd
->
open_tables
,
1
,
0
,
&
need_reopen
);
sql_handler_lock_error
.
init
();
thd
->
push_internal_handler
(
&
sql_handler_lock_error
);
lock
=
mysql_lock_tables
(
thd
,
&
thd
->
open_tables
,
1
,
0
);
thd
->
pop_internal_handler
();
/*
/*
In 5.1 and earlier, mysql_lock_tables() could replace the TABLE
In 5.1 and earlier, mysql_lock_tables() could replace the TABLE
object with another one (reopen it). This is no longer the case
object with another one (reopen it). This is no longer the case
...
@@ -517,7 +571,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
...
@@ -517,7 +571,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
/* Restore previous context. */
/* Restore previous context. */
thd
->
open_tables
=
backup_open_tables
;
thd
->
open_tables
=
backup_open_tables
;
if
(
need_reopen
)
if
(
sql_handler_lock_error
.
need_reopen
()
)
{
{
mysql_ha_close_table
(
thd
,
hash_tables
);
mysql_ha_close_table
(
thd
,
hash_tables
);
goto
retry
;
goto
retry
;
...
...
sql/sql_insert.cc
View file @
7116431a
...
@@ -2396,7 +2396,8 @@ void kill_delayed_threads(void)
...
@@ -2396,7 +2396,8 @@ void kill_delayed_threads(void)
bool
Delayed_insert
::
open_and_lock_table
()
bool
Delayed_insert
::
open_and_lock_table
()
{
{
if
(
!
(
table
=
open_n_lock_single_table
(
&
thd
,
&
table_list
,
if
(
!
(
table
=
open_n_lock_single_table
(
&
thd
,
&
table_list
,
TL_WRITE_DELAYED
,
0
)))
TL_WRITE_DELAYED
,
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
)))
{
{
thd
.
fatal_error
();
// Abort waiting inserts
thd
.
fatal_error
();
// Abort waiting inserts
return
TRUE
;
return
TRUE
;
...
@@ -2557,7 +2558,6 @@ pthread_handler_t handle_delayed_insert(void *arg)
...
@@ -2557,7 +2558,6 @@ pthread_handler_t handle_delayed_insert(void *arg)
if
(
di
->
tables_in_use
&&
!
thd
->
lock
&&
!
thd
->
killed
)
if
(
di
->
tables_in_use
&&
!
thd
->
lock
&&
!
thd
->
killed
)
{
{
bool
need_reopen
;
/*
/*
Request for new delayed insert.
Request for new delayed insert.
Lock the table, but avoid to be blocked by a global read lock.
Lock the table, but avoid to be blocked by a global read lock.
...
@@ -2568,30 +2568,10 @@ pthread_handler_t handle_delayed_insert(void *arg)
...
@@ -2568,30 +2568,10 @@ pthread_handler_t handle_delayed_insert(void *arg)
handler will close the table and finish when the outstanding
handler will close the table and finish when the outstanding
inserts are done.
inserts are done.
*/
*/
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
0
)))
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
,
&
need_reopen
)))
{
{
if
(
need_reopen
&&
!
thd
->
killed
)
/* Fatal error */
{
thd
->
killed
=
THD
::
KILL_CONNECTION
;
/*
We were waiting to obtain TL_WRITE_DELAYED (probably due to
someone having or requesting TL_WRITE_ALLOW_READ) and got
aborted. Try to reopen table and if it fails die.
*/
TABLE_LIST
*
tl_ptr
=
&
di
->
table_list
;
close_tables_for_reopen
(
thd
,
&
tl_ptr
,
NULL
);
di
->
table
=
0
;
if
(
di
->
open_and_lock_table
())
{
thd
->
killed
=
THD
::
KILL_CONNECTION
;
}
}
else
{
/* Fatal error */
thd
->
killed
=
THD
::
KILL_CONNECTION
;
}
}
}
mysql_cond_broadcast
(
&
di
->
cond_client
);
mysql_cond_broadcast
(
&
di
->
cond_client
);
}
}
...
@@ -3542,7 +3522,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
...
@@ -3542,7 +3522,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
List_iterator_fast
<
Item
>
it
(
*
items
);
List_iterator_fast
<
Item
>
it
(
*
items
);
Item
*
item
;
Item
*
item
;
Field
*
tmp_field
;
Field
*
tmp_field
;
bool
not_used
;
DBUG_ENTER
(
"create_table_from_items"
);
DBUG_ENTER
(
"create_table_from_items"
);
tmp_table
.
alias
=
0
;
tmp_table
.
alias
=
0
;
...
@@ -3667,7 +3646,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
...
@@ -3667,7 +3646,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
the table) and thus can't get aborted.
the table) and thus can't get aborted.
*/
*/
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
MYSQL_LOCK_IGNORE_FLUSH
,
&
not_used
))
||
MYSQL_LOCK_IGNORE_FLUSH
))
||
hooks
->
postlock
(
&
table
,
1
))
hooks
->
postlock
(
&
table
,
1
))
{
{
if
(
*
lock
)
if
(
*
lock
)
...
...
sql/sql_table.cc
View file @
7116431a
...
@@ -1811,7 +1811,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
...
@@ -1811,7 +1811,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
my_bool
drop_temporary
)
my_bool
drop_temporary
)
{
{
bool
error
;
bool
error
;
Drop_table_error_handler
err_handler
(
thd
->
get_internal_handler
())
;
Drop_table_error_handler
err_handler
;
DBUG_ENTER
(
"mysql_rm_table"
);
DBUG_ENTER
(
"mysql_rm_table"
);
...
...
sql/sql_update.cc
View file @
7116431a
...
@@ -203,33 +203,26 @@ int mysql_update(THD *thd,
...
@@ -203,33 +203,26 @@ int mysql_update(THD *thd,
SQL_SELECT
*
select
;
SQL_SELECT
*
select
;
READ_RECORD
info
;
READ_RECORD
info
;
SELECT_LEX
*
select_lex
=
&
thd
->
lex
->
select_lex
;
SELECT_LEX
*
select_lex
=
&
thd
->
lex
->
select_lex
;
bool
need_reopen
;
ulonglong
id
;
ulonglong
id
;
List
<
Item
>
all_fields
;
List
<
Item
>
all_fields
;
THD
::
killed_state
killed_status
=
THD
::
NOT_KILLED
;
THD
::
killed_state
killed_status
=
THD
::
NOT_KILLED
;
MDL_ticket
*
start_of_statement_svp
=
thd
->
mdl_context
.
mdl_savepoint
();
MDL_ticket
*
start_of_statement_svp
=
thd
->
mdl_context
.
mdl_savepoint
();
DBUG_ENTER
(
"mysql_update"
);
DBUG_ENTER
(
"mysql_update"
);
for
(
;
;
)
if
(
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
{
DBUG_RETURN
(
1
);
if
(
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
DBUG_RETURN
(
1
);
if
(
table_list
->
multitable_view
)
if
(
table_list
->
multitable_view
)
{
{
DBUG_ASSERT
(
table_list
->
view
!=
0
);
DBUG_ASSERT
(
table_list
->
view
!=
0
);
DBUG_PRINT
(
"info"
,
(
"Switch to multi-update"
));
DBUG_PRINT
(
"info"
,
(
"Switch to multi-update"
));
/* pass counter value */
/* pass counter value */
thd
->
lex
->
table_count
=
table_count
;
thd
->
lex
->
table_count
=
table_count
;
/* convert to multiupdate */
/* convert to multiupdate */
DBUG_RETURN
(
2
);
DBUG_RETURN
(
2
);
}
if
(
!
lock_tables
(
thd
,
table_list
,
table_count
,
0
,
&
need_reopen
))
break
;
if
(
!
need_reopen
)
DBUG_RETURN
(
1
);
close_tables_for_reopen
(
thd
,
&
table_list
,
start_of_statement_svp
);
}
}
if
(
lock_tables
(
thd
,
table_list
,
table_count
,
0
))
DBUG_RETURN
(
1
);
if
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
if
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
thd
->
fill_derived_tables
()
&&
(
thd
->
fill_derived_tables
()
&&
...
@@ -963,17 +956,14 @@ int mysql_multi_update_prepare(THD *thd)
...
@@ -963,17 +956,14 @@ int mysql_multi_update_prepare(THD *thd)
uint
table_count
=
lex
->
table_count
;
uint
table_count
=
lex
->
table_count
;
const
bool
using_lock_tables
=
thd
->
locked_tables_mode
!=
LTM_NONE
;
const
bool
using_lock_tables
=
thd
->
locked_tables_mode
!=
LTM_NONE
;
bool
original_multiupdate
=
(
thd
->
lex
->
sql_command
==
SQLCOM_UPDATE_MULTI
);
bool
original_multiupdate
=
(
thd
->
lex
->
sql_command
==
SQLCOM_UPDATE_MULTI
);
bool
need_reopen
=
FALSE
;
MDL_ticket
*
start_of_statement_svp
=
thd
->
mdl_context
.
mdl_savepoint
();
MDL_ticket
*
start_of_statement_svp
=
thd
->
mdl_context
.
mdl_savepoint
();
DBUG_ENTER
(
"mysql_multi_update_prepare"
);
DBUG_ENTER
(
"mysql_multi_update_prepare"
);
/* following need for prepared statements, to run next time multi-update */
/* following need for prepared statements, to run next time multi-update */
thd
->
lex
->
sql_command
=
SQLCOM_UPDATE_MULTI
;
thd
->
lex
->
sql_command
=
SQLCOM_UPDATE_MULTI
;
reopen_tables:
/* open tables and create derived ones, but do not lock and fill them */
/* open tables and create derived ones, but do not lock and fill them */
if
((
(
original_multiupdate
||
need_reopen
)
&&
if
((
original_multiupdate
&&
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
||
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
||
mysql_handle_derived
(
lex
,
&
mysql_derived_prepare
))
mysql_handle_derived
(
lex
,
&
mysql_derived_prepare
))
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
...
@@ -1089,58 +1079,11 @@ int mysql_multi_update_prepare(THD *thd)
...
@@ -1089,58 +1079,11 @@ int mysql_multi_update_prepare(THD *thd)
/* now lock and fill tables */
/* now lock and fill tables */
if
(
!
thd
->
stmt_arena
->
is_stmt_prepare
()
&&
if
(
!
thd
->
stmt_arena
->
is_stmt_prepare
()
&&
lock_tables
(
thd
,
table_list
,
table_count
,
0
,
&
need_reopen
))
lock_tables
(
thd
,
table_list
,
table_count
,
0
))
{
{
if
(
!
need_reopen
)
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
DBUG_PRINT
(
"info"
,
(
"lock_tables failed, reopening"
));
/*
We have to reopen tables since some of them were altered or dropped
during lock_tables() or something was done with their triggers.
Let us do some cleanups to be able do setup_table() and setup_fields()
once again.
*/
List_iterator_fast
<
Item
>
it
(
*
fields
);
Item
*
item
;
while
((
item
=
it
++
))
item
->
cleanup
();
/*
To not to hog memory (as a result of the
unit->reinit_exec_mechanism() call below):
*/
lex
->
unit
.
cleanup
();
for
(
SELECT_LEX
*
sl
=
lex
->
all_selects_list
;
sl
;
sl
=
sl
->
next_select_in_list
())
{
SELECT_LEX_UNIT
*
unit
=
sl
->
master_unit
();
unit
->
reinit_exec_mechanism
();
// reset unit->prepared flags
/*
Reset 'clean' flag back to force normal execution of
unit->cleanup() in Prepared_statement::cleanup_stmt()
(call to lex->unit.cleanup() above sets this flag to TRUE).
*/
unit
->
unclean
();
}
/*
Also we need to cleanup Natural_join_column::table_field items.
To not to traverse a join tree we will cleanup whole
thd->free_list (in PS execution mode that list may not contain
items from 'fields' list, so the cleanup above is necessary to.
*/
cleanup_items
(
thd
->
free_list
);
cleanup_items
(
thd
->
stmt_arena
->
free_list
);
close_tables_for_reopen
(
thd
,
&
table_list
,
start_of_statement_svp
);
DEBUG_SYNC
(
thd
,
"multi_update_reopen_tables"
);
goto
reopen_tables
;
}
}
/* @todo: downgrade the metadata locks here. */
/*
/*
Check that we are not using table that we are updating, but we should
Check that we are not using table that we are updating, but we should
...
...
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