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);;
#
# Switching to connection 'handler_con1'.
# 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;
unlock tables;
# Switching to connection 'handler_con2'.
# Wait until ALTER is blocked during upgrade.
#
# Switching to connection 'default'.
# Reap INSERT.
ERROR HY000: Wait on a lock was aborted due to a pending exclusive lock
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
# lock is blocked by HANDLER which is open in connection currently
# waiting to get SW lock on the same table.
...
...
@@ -2248,6 +2255,8 @@ SET DEBUG_SYNC= 'RESET';
# Bug#50786 Assertion `thd->mdl_context.trans_sentinel() == __null'
# 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;
CREATE TABLE t1 (i INT);
CREATE TABLE t2 (i INT);
...
...
@@ -2271,7 +2280,6 @@ SET DEBUG_SYNC= 'now WAIT_FOR parked';
# Sending:
SELECT 1;
# connection: con3
# Sending:
ALTER TABLE t1 ADD COLUMN j INT;
# connection: default
SET DEBUG_SYNC= 'now SIGNAL go';
...
...
@@ -2284,8 +2292,6 @@ HANDLER t1 CLOSE;
# Reaping SELECT 1
1
1
# connection: con3
# Reaping ALTER TABLE t1 ADD COLUMN j INT
# connection: default
DROP TABLE t1, t2;
SET DEBUG_SYNC= 'RESET';
...
...
mysql-test/t/mdl_sync.test
View file @
7116431a
...
...
@@ -2277,17 +2277,32 @@ let $wait_condition=
select
count
(
*
)
=
1
from
information_schema
.
processlist
where
state
=
"Table lock"
and
info
=
"insert into t2 values (1)"
;
--
source
include
/
wait_condition
.
inc
--
echo
# The below statement should not cause deadlock.
alter
table
t1
drop
column
j
;
unlock
tables
;
--
echo
# Sending 'alter table t1 drop column j'. It should not cause
--
echo
# deadlock.
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
# Switching to connection 'default'.
connection
default
;
--
echo
# Reap INSERT.
--
error
ER_LOCK_ABORTED
--
reap
handler
t1
close
;
--
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
# lock is blocked by HANDLER which is open in connection currently
--
echo
# waiting to get SW lock on the same table.
...
...
@@ -3220,6 +3235,8 @@ disconnect con2;
--
echo
# failed in open_ltable()
--
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
DROP
TABLE
IF
EXISTS
t1
,
t2
;
--
enable_warnings
...
...
@@ -3279,16 +3296,10 @@ let $wait_condition=
# 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
# triggered the assert.
--
echo
# Sending:
--
send
ALTER
TABLE
t1
ADD
COLUMN
j
INT
ALTER
TABLE
t1
ADD
COLUMN
j
INT
;
--
echo
# 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'
;
--
echo
# connection: con1
...
...
@@ -3302,11 +3313,6 @@ connection con2;
--
echo
# Reaping SELECT 1
--
reap
--
echo
# connection: con3
connection
con3
;
--
echo
# Reaping ALTER TABLE t1 ADD COLUMN j INT
--
reap
--
echo
# connection: default
connection
default
;
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)
thd
->
proc_info
=
"Opening "
NDB_REP_DB
"."
NDB_REP_TABLE
;
tables
->
required_type
=
FRMTYPE_TABLE
;
uint
counter
;
thd
->
clear_error
();
if
(
open_and_lock_tables
(
thd
,
tables
,
FALSE
,
0
))
{
...
...
@@ -2374,7 +2373,6 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
{
ndb_binlog_index_row
&
row
=
*
(
ndb_binlog_index_row
*
)
_row
;
int
error
=
0
;
bool
need_reopen
;
/*
Turn of binlogging to prevent the table changes to be written to
the binary log.
...
...
sql/lock.cc
View file @
7116431a
...
...
@@ -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 */
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.
...
...
@@ -108,8 +108,7 @@ static int thr_lock_errno_to_mysql[]=
@return 0 if all the check passed, non zero if a check failed.
*/
static
int
lock_tables_check
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
bool
*
write_lock_used
,
uint
flags
)
lock_tables_check
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
)
{
uint
system_count
,
i
;
bool
is_superuser
,
log_table_write_query
;
...
...
@@ -117,7 +116,6 @@ lock_tables_check(THD *thd, TABLE **tables, uint count,
DBUG_ENTER
(
"lock_tables_check"
);
system_count
=
0
;
*
write_lock_used
=
FALSE
;
is_superuser
=
thd
->
security_ctx
->
master_access
&
SUPER_ACL
;
log_table_write_query
=
(
is_log_table_write_query
(
thd
->
lex
->
sql_command
)
||
((
flags
&
MYSQL_LOCK_PERF_SCHEMA
)
!=
0
));
...
...
@@ -153,8 +151,6 @@ lock_tables_check(THD *thd, TABLE **tables, uint count,
if
(
t
->
reginfo
.
lock_type
>=
TL_WRITE_ALLOW_WRITE
)
{
*
write_lock_used
=
TRUE
;
if
(
t
->
s
->
table_category
==
TABLE_CATEGORY_SYSTEM
)
system_count
++
;
...
...
@@ -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 count The number of tables to lock.
@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_FLUSH Ignore a flush tables.
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
reopen table unless there are external invariants which guarantee
...
...
@@ -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.
*/
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
,
bool
*
need_reopen
)
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
)
{
int
rc
;
MYSQL_LOCK
*
sql_lock
;
bool
write_lock_used
;
DBUG_ENTER
(
"mysql_lock_tables"
);
*
need_reopen
=
FALSE
;
if
(
lock_tables_check
(
thd
,
tables
,
count
,
&
write_lock_used
,
flags
))
if
(
lock_tables_check
(
thd
,
tables
,
count
,
flags
))
DBUG_RETURN
(
NULL
);
ulong
timeout
=
(
flags
&
MYSQL_LOCK_IGNORE_TIMEOUT
)
?
LONG_TIMEOUT
:
thd
->
variables
.
lock_wait_timeout
;
for
(;;)
{
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
);
if
(
!
(
sql_lock
=
get_lock_data
(
thd
,
tables
,
count
,
GET_LOCK_STORE_LOCKS
)))
DBUG_RETURN
(
NULL
);
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
)
(
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
);
retry:
/* Let upper level close all used tables and retry or give error. */
*
need_reopen
=
TRUE
;
break
;
if
(
!
thd
->
killed
)
my_error
(
rc
,
MYF
(
0
));
}
end:
thd_proc_info
(
thd
,
0
);
if
(
thd
->
killed
)
{
thd
->
send_kill_message
();
if
(
sql_lock
)
{
mysql_unlock_tables
(
thd
,
sql_lock
);
sql_lock
=
0
;
mysql_unlock_tables
(
thd
,
sql_lock
);
sql_lock
=
0
;
}
}
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)
*/
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
initialized. Contrary to in
...
...
@@ -1465,80 +1463,31 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
lex_start
(
thd
);
while
((
error
=
lock_tables
(
thd
,
rli
->
tables_to_lock
,
rli
->
tables_to_lock_count
,
0
,
&
need_reopen
)))
if
((
error
=
lock_tables
(
thd
,
rli
->
tables_to_lock
,
rli
->
tables_to_lock_count
,
0
)))
{
if
(
!
need_reopen
)
{
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
)
if
(
thd
->
is_slave_error
||
thd
->
is_fatal_error
)
{
rli
->
report
(
ERROR_LEVEL
,
ER_SLAVE_FATAL_ERROR
,
ER
(
ER_SLAVE_FATAL_ERROR
),
"call to binlog_flush_pending_rows_event() failed"
);
thd
->
is_slave_error
=
1
;
DBUG_RETURN
(
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
;
}
TABLE_LIST
*
tables
=
rli
->
tables_to_lock
;
close_tables_for_reopen
(
thd
,
&
tables
,
NULL
);
uint
tables_count
=
rli
->
tables_to_lock_count
;
if
((
error
=
open_tables
(
thd
,
&
tables
,
&
tables_count
,
0
)))
else
{
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' 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
);
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
);
}
/*
...
...
sql/mysql_priv.h
View file @
7116431a
...
...
@@ -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
,
thr_lock_type
lock_type
,
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
*
need_reopen
);
bool
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
counter
,
uint
flags
);
TABLE
*
open_temporary_table
(
THD
*
thd
,
const
char
*
path
,
const
char
*
db
,
const
char
*
table_name
,
bool
link_in_list
);
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,
extern
struct
st_VioSSLFd
*
ssl_acceptor_fd
;
#endif
/* HAVE_OPENSSL */
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
uint
flags
,
bool
*
need_reopen
);
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
uint
flags
);
/* mysql_lock_tables() and open_table() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#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
ER_TOO_LONG_INDEX_COMMENT
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,
key_length
=
(
create_table_def_key
(
thd
,
key
,
table_list
,
1
)
-
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
of temporary tables of this thread. In MySQL temporary tables
...
...
@@ -3293,7 +3318,6 @@ bool
Locked_tables_list
::
reopen_tables
(
THD
*
thd
)
{
Open_table_context
ot_ctx_unused
(
thd
,
LONG_TIMEOUT
);
bool
lt_refresh_unused
;
size_t
reopen_count
=
0
;
MYSQL_LOCK
*
lock
;
MYSQL_LOCK
*
merged_lock
;
...
...
@@ -3333,7 +3357,7 @@ Locked_tables_list::reopen_tables(THD *thd)
break something else.
*/
lock
=
mysql_lock_tables
(
thd
,
m_reopen_array
,
reopen_count
,
MYSQL_OPEN_REOPEN
,
&
lt_refresh_unused
);
MYSQL_OPEN_REOPEN
);
thd
->
in_lock_tables
=
0
;
if
(
lock
==
NULL
||
(
merged_lock
=
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,
TABLE
*
table
;
Open_table_context
ot_ctx
(
thd
,
(
lock_flags
&
MYSQL_LOCK_IGNORE_TIMEOUT
)
?
LONG_TIMEOUT
:
thd
->
variables
.
lock_wait_timeout
);
bool
refresh
;
bool
error
;
DBUG_ENTER
(
"open_ltable"
);
...
...
@@ -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 */
table_list
->
required_type
=
FRMTYPE_TABLE
;
retry:
while
((
error
=
open_table
(
thd
,
table_list
,
thd
->
mem_root
,
&
ot_ctx
,
0
))
&&
while
((
error
=
open_table
(
thd
,
table_list
,
thd
->
mem_root
,
&
ot_ctx
,
lock_flags
))
&&
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,
DBUG_ASSERT
(
thd
->
lock
==
0
);
// You must lock everything at once
if
((
table
->
reginfo
.
lock_type
=
lock_type
)
!=
TL_UNLOCK
)
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table_list
->
table
,
1
,
lock_flags
,
&
refresh
)))
lock_flags
)))
{
if
(
refresh
)
{
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
;
table
=
0
;
}
}
}
...
...
@@ -5168,7 +5181,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
Prelocking_strategy
*
prelocking_strategy
)
{
uint
counter
;
bool
need_reopen
;
/*
Remember the set of metadata locks which this connection
managed to acquire before the start of the current statement.
...
...
@@ -5182,28 +5194,24 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
DBUG_ENTER
(
"open_and_lock_tables"
);
DBUG_PRINT
(
"enter"
,
(
"derived handling: %d"
,
derived
));
for
(
;
;
)
{
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
flags
,
prelocking_strategy
))
DBUG_RETURN
(
TRUE
);
DBUG_EXECUTE_IF
(
"sleep_open_and_lock_after_open"
,
{
const
char
*
old_proc_info
=
thd
->
proc_info
;
thd
->
proc_info
=
"DBUG sleep"
;
my_sleep
(
6000000
);
thd
->
proc_info
=
old_proc_info
;});
if
(
!
lock_tables
(
thd
,
tables
,
counter
,
flags
,
&
need_reopen
))
break
;
if
(
!
need_reopen
)
DBUG_RETURN
(
TRUE
);
close_tables_for_reopen
(
thd
,
&
tables
,
start_of_statement_svp
);
}
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
flags
,
prelocking_strategy
))
DBUG_RETURN
(
TRUE
);
DBUG_EXECUTE_IF
(
"sleep_open_and_lock_after_open"
,
{
const
char
*
old_proc_info
=
thd
->
proc_info
;
thd
->
proc_info
=
"DBUG sleep"
;
my_sleep
(
6000000
);
thd
->
proc_info
=
old_proc_info
;});
if
(
lock_tables
(
thd
,
tables
,
counter
,
flags
))
DBUG_RETURN
(
TRUE
);
if
(
derived
&&
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
thd
->
fill_derived_tables
()
&&
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_filling
))))
DBUG_RETURN
(
TRUE
);
/* purecov: inspected */
DBUG_RETURN
(
FALSE
);
}
...
...
@@ -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
lock_tables()
thd Thread handler
tables Tables to lock
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).
@param thd Thread handler
@param tables Tables to lock
@param count Number of opened tables
@param flags Options (see mysql_lock_tables() for details)
NOTES
You can't call lock_tables twice, as this would break the dead-lock-free
handling thr_lock gives us. You most always get all needed locks at
once.
You can't call lock_tables() while holding thr_lock locks, as
this would break the dead-lock-free handling thr_lock gives us.
You most always get all needed locks at once.
If query for which we are calling this function marked as requiring
prelocking, this function will change locked_tables_mode to
LTM_PRELOCKED.
If the query for which we are calling this function is marked as
requiring prelocking, this function will change
locked_tables_mode to
LTM_PRELOCKED.
RETURN VALUES
0 ok
-1 Error
@retval FALSE Success.
@retval TRUE A lock wait timeout, deadlock or out of memory.
*/
bool
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
count
,
uint
flags
,
bool
*
need_reopen
)
uint
flags
)
{
TABLE_LIST
*
table
;
...
...
@@ -5302,7 +5301,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
*/
DBUG_ASSERT
(
thd
->
locked_tables_mode
<=
LTM_LOCK_TABLES
||
!
thd
->
lex
->
requires_prelocking
());
*
need_reopen
=
FALSE
;
if
(
!
tables
&&
!
thd
->
lex
->
requires_prelocking
())
DBUG_RETURN
(
thd
->
decide_logging_format
(
tables
));
...
...
@@ -5347,7 +5345,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
DEBUG_SYNC
(
thd
,
"before_lock_tables_takes_lock"
);
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
(
uint
)
(
ptr
-
start
),
flags
,
need_reopen
)))
flags
)))
DBUG_RETURN
(
TRUE
);
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)
open tables cannot be accepted when restoring the open tables
state.
*/
if
(
thd
->
killed
)
close_thread_tables
(
thd
);
close_thread_tables
(
thd
);
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
class
Drop_table_error_handler
:
public
Internal_error_handler
{
public:
Drop_table_error_handler
(
Internal_error_handler
*
err_handler
)
:
m_err_handler
(
err_handler
)
{
}
Drop_table_error_handler
()
{}
public:
bool
handle_condition
(
THD
*
thd
,
...
...
@@ -1174,7 +1172,6 @@ class Drop_table_error_handler : public Internal_error_handler
MYSQL_ERROR
**
cond_hdl
);
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)
}
else
{
Drop_table_error_handler
err_handler
(
thd
->
get_internal_handler
())
;
Drop_table_error_handler
err_handler
;
thd
->
push_internal_handler
(
&
err_handler
);
error
=
-
1
;
...
...
sql/sql_handler.cc
View file @
7116431a
...
...
@@ -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.
...
...
@@ -442,7 +492,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint
num_rows
;
uchar
*
UNINIT_VAR
(
key
);
uint
UNINIT_VAR
(
key_len
);
bool
need_reopen
;
Sql_handler_lock_error_handler
sql_handler_lock_error
;
DBUG_ENTER
(
"mysql_ha_read"
);
DBUG_PRINT
(
"enter"
,(
"'%s'.'%s' as '%s'"
,
tables
->
db
,
tables
->
table_name
,
tables
->
alias
));
...
...
@@ -506,8 +556,12 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
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
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,
/* Restore previous context. */
thd
->
open_tables
=
backup_open_tables
;
if
(
need_reopen
)
if
(
sql_handler_lock_error
.
need_reopen
()
)
{
mysql_ha_close_table
(
thd
,
hash_tables
);
goto
retry
;
...
...
sql/sql_insert.cc
View file @
7116431a
...
...
@@ -2396,7 +2396,8 @@ void kill_delayed_threads(void)
bool
Delayed_insert
::
open_and_lock_table
()
{
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
return
TRUE
;
...
...
@@ -2557,7 +2558,6 @@ pthread_handler_t handle_delayed_insert(void *arg)
if
(
di
->
tables_in_use
&&
!
thd
->
lock
&&
!
thd
->
killed
)
{
bool
need_reopen
;
/*
Request for new delayed insert.
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)
handler will close the table and finish when the outstanding
inserts are done.
*/
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
,
&
need_reopen
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
0
)))
{
if
(
need_reopen
&&
!
thd
->
killed
)
{
/*
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
;
}
/* Fatal error */
thd
->
killed
=
THD
::
KILL_CONNECTION
;
}
mysql_cond_broadcast
(
&
di
->
cond_client
);
}
...
...
@@ -3542,7 +3522,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
List_iterator_fast
<
Item
>
it
(
*
items
);
Item
*
item
;
Field
*
tmp_field
;
bool
not_used
;
DBUG_ENTER
(
"create_table_from_items"
);
tmp_table
.
alias
=
0
;
...
...
@@ -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.
*/
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
MYSQL_LOCK_IGNORE_FLUSH
,
&
not_used
))
||
MYSQL_LOCK_IGNORE_FLUSH
))
||
hooks
->
postlock
(
&
table
,
1
))
{
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,
my_bool
drop_temporary
)
{
bool
error
;
Drop_table_error_handler
err_handler
(
thd
->
get_internal_handler
())
;
Drop_table_error_handler
err_handler
;
DBUG_ENTER
(
"mysql_rm_table"
);
...
...
sql/sql_update.cc
View file @
7116431a
...
...
@@ -203,33 +203,26 @@ int mysql_update(THD *thd,
SQL_SELECT
*
select
;
READ_RECORD
info
;
SELECT_LEX
*
select_lex
=
&
thd
->
lex
->
select_lex
;
bool
need_reopen
;
ulonglong
id
;
List
<
Item
>
all_fields
;
THD
::
killed_state
killed_status
=
THD
::
NOT_KILLED
;
MDL_ticket
*
start_of_statement_svp
=
thd
->
mdl_context
.
mdl_savepoint
();
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
)
{
DBUG_ASSERT
(
table_list
->
view
!=
0
);
DBUG_PRINT
(
"info"
,
(
"Switch to multi-update"
));
/* pass counter value */
thd
->
lex
->
table_count
=
table_count
;
/* convert to multiupdate */
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
(
table_list
->
multitable_view
)
{
DBUG_ASSERT
(
table_list
->
view
!=
0
);
DBUG_PRINT
(
"info"
,
(
"Switch to multi-update"
));
/* pass counter value */
thd
->
lex
->
table_count
=
table_count
;
/* convert to multiupdate */
DBUG_RETURN
(
2
);
}
if
(
lock_tables
(
thd
,
table_list
,
table_count
,
0
))
DBUG_RETURN
(
1
);
if
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
thd
->
fill_derived_tables
()
&&
...
...
@@ -963,17 +956,14 @@ int mysql_multi_update_prepare(THD *thd)
uint
table_count
=
lex
->
table_count
;
const
bool
using_lock_tables
=
thd
->
locked_tables_mode
!=
LTM_NONE
;
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
();
DBUG_ENTER
(
"mysql_multi_update_prepare"
);
/* following need for prepared statements, to run next time multi-update */
thd
->
lex
->
sql_command
=
SQLCOM_UPDATE_MULTI
;
reopen_tables:
/* 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
))
||
mysql_handle_derived
(
lex
,
&
mysql_derived_prepare
))
DBUG_RETURN
(
TRUE
);
...
...
@@ -1089,58 +1079,11 @@ int mysql_multi_update_prepare(THD *thd)
/* now lock and fill tables */
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_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
;
DBUG_RETURN
(
TRUE
);
}
/* @todo: downgrade the metadata locks here. */
/*
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