Merge from mysql-5.5-runtime to mysql-5.5-bugfixing.

This commit is contained in:
Jon Olav Hauglid 2010-08-20 10:24:32 +02:00
commit 39ac44d660
107 changed files with 2941 additions and 1517 deletions

View File

@ -997,6 +997,7 @@ libmysqld/.deps/sql_cursor.Po
libmysqld/.deps/sql_db.Po
libmysqld/.deps/sql_delete.Po
libmysqld/.deps/sql_truncate.Po
libmysqld/.deps/sql_reload.Po
libmysqld/.deps/datadict.Po
libmysqld/.deps/sql_derived.Po
libmysqld/.deps/sql_do.Po
@ -1175,6 +1176,7 @@ libmysqld/sql_cursor.h
libmysqld/sql_db.cc
libmysqld/sql_delete.cc
libmysqld/sql_truncate.cc
libmysqld/sql_reload.cc
libmysqld/datadict.cc
libmysqld/sql_derived.cc
libmysqld/sql_do.cc
@ -2067,6 +2069,7 @@ sql/.deps/sql_cursor.Po
sql/.deps/sql_db.Po
sql/.deps/sql_delete.Po
sql/.deps/sql_truncate.Po
sql/.deps/sql_reload.Po
sql/.deps/datadict.Po
sql/.deps/sql_derived.Po
sql/.deps/sql_do.Po

View File

@ -782,7 +782,7 @@ dnl Emits shell script for checking configure arguments
dnl Arguments to this macro is default value for selected plugins
AC_DEFUN([_MYSQL_CHECK_PLUGIN_ARGS],[
__MYSQL_CHECK_PLUGIN_ARGS(m4_default([$1], [none]))
__MYSQL_CHECK_PLUGIN_ARGS(m4_default([$1], [default]))
])
AC_DEFUN([__MYSQL_CHECK_PLUGIN_ARGS],[

View File

@ -2606,7 +2606,7 @@ MYSQL_STORAGE_ENGINE(partition, partition, [Partition Support],
dnl -- ndbcluster requires partition to be enabled
MYSQL_CONFIGURE_PLUGINS([none])
MYSQL_CONFIGURE_PLUGINS([default])
# Only build client code?
AC_ARG_WITH(server,

View File

@ -601,6 +601,8 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp);
#define rw_trywrlock(A) my_rw_trywrlock((A))
#define rw_unlock(A) my_rw_unlock((A))
#define rwlock_destroy(A) my_rw_destroy((A))
#define rw_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A))
#define rw_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A))
#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */
@ -624,6 +626,8 @@ extern int rw_pr_init(rw_pr_lock_t *);
#define rw_pr_trywrlock(A) pthread_rwlock_trywrlock(A)
#define rw_pr_unlock(A) pthread_rwlock_unlock(A)
#define rw_pr_destroy(A) pthread_rwlock_destroy(A)
#define rw_pr_lock_assert_write_owner(A)
#define rw_pr_lock_assert_not_write_owner(A)
#else
/* Otherwise we have to use our own implementation of read/write locks. */
#define NEED_MY_RW_LOCK 1
@ -636,6 +640,8 @@ extern int rw_pr_init(struct st_my_rw_lock_t *);
#define rw_pr_trywrlock(A) my_rw_trywrlock((A))
#define rw_pr_unlock(A) my_rw_unlock((A))
#define rw_pr_destroy(A) my_rw_destroy((A))
#define rw_pr_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A))
#define rw_pr_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A))
#endif /* defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) */
@ -651,6 +657,9 @@ typedef struct st_my_rw_lock_t {
int state; /* -1:writer,0:free,>0:readers */
int waiters; /* number of waiting writers */
my_bool prefer_readers;
#ifdef SAFE_MUTEX
pthread_t write_thread;
#endif
} my_rw_lock_t;
extern int my_rw_init(my_rw_lock_t *, my_bool *);
@ -660,6 +669,17 @@ extern int my_rw_wrlock(my_rw_lock_t *);
extern int my_rw_unlock(my_rw_lock_t *);
extern int my_rw_tryrdlock(my_rw_lock_t *);
extern int my_rw_trywrlock(my_rw_lock_t *);
#ifdef SAFE_MUTEX
#define my_rw_lock_assert_write_owner(A) \
DBUG_ASSERT((A)->state == -1 && pthread_equal(pthread_self(), \
(A)->write_thread))
#define my_rw_lock_assert_not_write_owner(A) \
DBUG_ASSERT((A)->state >= 0 || ! pthread_equal(pthread_self(), \
(A)->write_thread))
#else
#define my_rw_lock_assert_write_owner(A)
#define my_rw_lock_assert_not_write_owner(A)
#endif
#endif /* NEED_MY_RW_LOCK */

View File

@ -215,6 +215,14 @@ typedef struct st_mysql_cond mysql_cond_t;
#define mysql_mutex_assert_not_owner(M) \
safe_mutex_assert_not_owner(&(M)->m_mutex)
/** Wrappers for instrumented prlock objects. */
#define mysql_prlock_assert_write_owner(M) \
rw_pr_lock_assert_write_owner(&(M)->m_prlock)
#define mysql_prlock_assert_not_write_owner(M) \
rw_pr_lock_assert_not_write_owner(&(M)->m_prlock)
/**
@def mysql_mutex_init(K, M, A)
Instrumented mutex_init.

View File

@ -64,7 +64,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/sql_db.cc ../sql/sql_delete.cc ../sql/sql_derived.cc
../sql/sql_do.cc ../sql/sql_error.cc ../sql/sql_handler.cc
../sql/sql_help.cc ../sql/sql_insert.cc ../sql/datadict.cc
../sql/sql_admin.cc ../sql/sql_truncate.cc
../sql/sql_admin.cc ../sql/sql_truncate.cc ../sql/sql_reload.cc
../sql/sql_lex.cc ../sql/keycaches.cc
../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc
../sql/sql_binlog.cc ../sql/sql_manager.cc

View File

@ -64,6 +64,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
opt_sum.cc procedure.cc records.cc sql_acl.cc \
sql_load.cc discover.cc sql_locale.cc \
sql_profile.cc sql_admin.cc sql_truncate.cc datadict.cc \
sql_reload.cc \
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
sql_lex.cc sql_list.cc sql_manager.cc \

View File

@ -153,7 +153,7 @@ connection master;
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE info = "RENAME TABLE t1 TO t3, t2 TO t1" and
state = "Waiting for table";
state = "Waiting for table metadata lock";
--source include/wait_condition.inc
COMMIT;

View File

@ -43,7 +43,8 @@ connection default;
# of our statement.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "insert into $table (i) values (0)";
where state = "Waiting for table level lock" and
info = "insert into $table (i) values (0)";
--source include/wait_condition.inc
--disable_result_log

View File

@ -523,7 +523,7 @@ connection waiter;
--echo connection: waiter
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Flushing tables";
where state = "Waiting for table flush";
--source include/wait_condition.inc
connection default;
--echo connection: default
@ -557,7 +557,8 @@ connection waiter;
--echo connection: waiter
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "rename table t1 to t0";
where state = "Waiting for table metadata lock" and
info = "rename table t1 to t0";
--source include/wait_condition.inc
connection default;
--echo connection: default
@ -743,7 +744,8 @@ send alter table t1 engine=memory;
connection con2;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 engine=memory";
where state = "Waiting for table metadata lock" and
info = "alter table t1 engine=memory";
--source include/wait_condition.inc
connection default;
--error ER_ILLEGAL_HA
@ -764,7 +766,8 @@ send alter table t1 engine=memory;
connection con2;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 engine=memory";
where state = "Waiting for table metadata lock" and
info = "alter table t1 engine=memory";
--source include/wait_condition.inc
connection default;
--echo # Since S metadata lock was already acquired at HANDLER OPEN time
@ -1024,7 +1027,9 @@ connection con1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop table t1' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t1';
--source include/wait_condition.inc
--echo # --> connection default
connection default;
@ -1055,7 +1060,9 @@ connection con1;
--echo # --> connection con2
connection con2;
--echo # Waiting for 'drop table t1' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t1';
--source include/wait_condition.inc
--echo # --> connection default
connection default;
@ -1097,7 +1104,8 @@ send rename table t0 to t3, t1 to t0, t3 to t1;
connection con1;
--echo # Waiting for 'rename table ...' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='rename table t0 to t3, t1 to t0, t3 to t1';
where state='Waiting for table metadata lock' and
info='rename table t0 to t3, t1 to t0, t3 to t1';
--source include/wait_condition.inc
--echo # --> connection default
connection default;
@ -1137,7 +1145,9 @@ connection con2;
--echo # --> connection con1
connection con1;
--echo # Waiting for 'drop table t2' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t2';
--source include/wait_condition.inc
--echo # --> connection default
connection default;
@ -1146,7 +1156,9 @@ send select * from t2;
--echo # --> connection con1
connection con1;
--echo # Waiting for 'select * from t2' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='select * from t2';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='select * from t2';
unlock tables;
--echo # --> connection con2
connection con2;
@ -1190,10 +1202,14 @@ connection default;
--echo # --> connection con3
connection con3;
--echo # Waiting for 'drop table t1' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t1';
--source include/wait_condition.inc
--echo # Waiting for 'drop table t2' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t2';
--source include/wait_condition.inc
--echo # Demonstrate that t2 lock was released and t2 was dropped
--echo # after ROLLBACK TO SAVEPOINT
@ -1255,10 +1271,14 @@ connection default;
--echo # --> connection con3
connection con3;
--echo # Waiting for 'drop table t1' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t1';
--source include/wait_condition.inc
--echo # Waiting for 'drop table t2' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t2';
--source include/wait_condition.inc
--echo # Demonstrate that t2 lock was released and t2 was dropped
--echo # after ROLLBACK TO SAVEPOINT
@ -1314,7 +1334,9 @@ drop table t1, t2;
--echo # --> connection con2
connection con2;
--echo # Waiting for 'drop table t3' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t3';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t3';
--source include/wait_condition.inc
--echo # Demonstrate that ROLLBACK TO SAVEPOINT didn't release the handler
--echo # lock.
@ -1348,7 +1370,9 @@ send drop table t2;
--echo # --> connection con2
connection con2;
--echo # Waiting for 'drop table t2' to get blocked...
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table metadata lock' and
info='drop table t2';
--source include/wait_condition.inc
--echo # --> connection con1
connection con1;
@ -1400,7 +1424,8 @@ connection con2;
--echo # has read from the table commits.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "lock tables t1 write";
where state = "Waiting for table metadata lock" and
info = "lock tables t1 write";
--source include/wait_condition.inc
--echo # --> connection default
@ -1427,7 +1452,8 @@ connection con1;
--echo # Waiting for 'handler t1 read a next' to get blocked...
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "handler t1 read a next";
where state = "Waiting for table level lock" and
info = "handler t1 read a next";
--source include/wait_condition.inc
--echo # The below 'drop table t1' should be able to proceed without

View File

@ -1,10 +0,0 @@
disable_query_log;
disable_result_log;
set @have_thread_concurrency=0;
select @have_thread_concurrency:=1 from information_schema.global_variables where variable_name='thread_concurrency';
if (`select @have_thread_concurrency = 0`)
{
skip Need @@thread_concurrency;
}
enable_result_log;
enable_query_log;

View File

@ -1580,7 +1580,7 @@ connect (con1, localhost, root,,);
--echo # Connection default
connection default;
let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for table' AND info='TRUNCATE TABLE t1';
WHERE state='Waiting for table metadata lock' AND info='TRUNCATE TABLE t1';
--source include/wait_condition.inc
SELECT * FROM t1 ORDER BY a;
ROLLBACK;

View File

@ -116,3 +116,22 @@ OK: create event: database does not exist
delete from t1;
commit work;
drop database events_test;
#
# Bug#54105 assert in MDL_context::release_locks_stored_before
#
USE test;
DROP TABLE IF EXISTS t1, t2;
DROP EVENT IF EXISTS e1;
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
CREATE TABLE t2 (a INT);
CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY DO SELECT 1;
START TRANSACTION;
INSERT INTO t1 VALUES (1);
SAVEPOINT A;
SHOW CREATE EVENT e1;
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
e1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `e1` ON SCHEDULE EVERY 1 DAY STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci
SELECT * FROM t2;
a
ROLLBACK WORK TO SAVEPOINT A;
DROP TABLE t1, t2;

View File

@ -205,6 +205,51 @@ a
insert into t2 (a) values (3);
# --> connection default;
unlock tables;
#
# Check that "FLUSH TABLES <list> WITH READ LOCK" is
# compatible with active "FLUSH TABLES WITH READ LOCK".
# Vice versa it is not true, since tables read-locked by
# "FLUSH TABLES <list> WITH READ LOCK" can't be flushed.
flush tables with read lock;
# --> connection con1;
flush table t1 with read lock;
select * from t1;
a
1
unlock tables;
# --> connection default;
unlock tables;
#
# Check that FLUSH TABLES t1 WITH READ LOCK
# does not conflict with an existing FLUSH TABLES t2
# WITH READ LOCK.
#
flush table t1 with read lock;
# --> connection con1
flush table t2 with read lock;
unlock tables;
# --> connection default
unlock tables;
#
# Check that FLUSH TABLES t1 WITH READ LOCK
# does not conflict with SET GLOBAL read_only=1.
#
set global read_only=1;
# connection con1
flush table t1 with read lock;
unlock tables;
# connection default
set global read_only=0;
#
# Check that it's possible to read-lock
# tables locked with FLUSH TABLE <list> WITH READ LOCK.
#
flush tables t1, t2 with read lock;
# connection con1
lock table t1 read, t2 read;
unlock tables;
# connection default
unlock tables;
# --> connection con1
drop table t1, t2, t3;
#
@ -234,3 +279,97 @@ drop temporary table v1;
unlock tables;
drop view v2, v3;
drop table t1, v1;
#
# FLUSH TABLES <list> WITH READ LOCK and HANDLER
#
drop table if exists t1;
create table t1 (a int, key a (a));
insert into t1 (a) values (1), (2), (3);
handler t1 open;
handler t1 read a next;
a
1
handler t1 read a next;
a
2
flush tables t1 with read lock;
handler t1 read a next;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;
#
# Sic: lost handler position.
#
handler t1 read a next;
a
1
handler t1 close;
drop table t1;
#
# Bug#52117 Pending FLUSH TALBES <list> aborts
# transactions unnecessarily.
#
drop table if exists t1;
# --> conection default
create table t1 (a int);
begin;
select * from t1;
a
# --> connection con1
#
# Issue a LOCK TABLE t1 READ. We could use HANDLER t1 OPEN
# or a long-running select -- anything that
# prevents FLUSH TABLE t1 from immediate completion would do.
#
lock table t1 read;
# --> connection con2
#
# FLUSH TABLE expels the table definition from the cache.
# Sending 'flush table t1'...
flush table t1;
# --> connection default
# Let flush table sync in.
select * from t1;
# --> connection con1
select * from t1;
a
unlock tables;
# --> connection con2
# Reaping 'flush table t1'...
# --> connection default
# Reaping 'select * from t1'...
a
commit;
#
# Repeat the same test but with FLUSH TABLES
#
begin;
select * from t1;
a
# --> connection con1
#
# Issue a LOCK TABLE t1 READ.
#
lock table t1 read;
# --> connection con2
#
# FLUSH TABLES expels the table definition from the cache.
# Sending 'flush tables'...
flush tables;
# --> connection default
# Let flush table sync in.
select * from t1;
# --> connection con1
select * from t1;
a
unlock tables;
# --> connection con2
# Reaping 'flush tables'...
# --> connection default
# Reaping 'select * from t1'...
a
commit;
# Cleanup
# --> connection con1
# --> connection con2
# --> connection default
drop table t1;

View File

@ -89,3 +89,15 @@ UNIQUE_CONSTRAINT_NAME
NULL
drop table t2;
set foreign_key_checks = 1;
#
# Bug#55973 Assertion `thd->transaction.stmt.is_empty()'
# on CREATE TABLE .. SELECT I_S.PART
#
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
CREATE VIEW v1 AS SELECT 1;
CREATE TABLE t1 engine = InnoDB AS
SELECT * FROM information_schema.partitions
WHERE table_schema= 'test' AND table_name= 'v1';
DROP TABLE t1;
DROP VIEW v1;

View File

@ -2034,6 +2034,155 @@ set debug_sync='now SIGNAL go2';
# Switching to connection 'default'.
# Reaping ALTER. It should succeed and not produce ER_LOCK_DEADLOCK.
drop table t1;
#
# Now, test for a situation in which deadlock involves waiting not
# only in MDL subsystem but also for TDC. Such deadlocks should be
# successfully detected. If possible, they should be resolved without
# resorting to ER_LOCK_DEADLOCK error.
#
create table t1(i int);
create table t2(j int);
#
# First, let us check how we handle a simple scenario involving
# waits in MDL and TDC.
#
set debug_sync= 'RESET';
# Switching to connection 'deadlock_con1'.
# Start a statement, which will acquire SR metadata lock on t1, open it
# and then stop, before trying to acquire SW lock on t2 and opening it.
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
# Sending:
select * from t1 where i in (select j from t2 for update);
# Switching to connection 'deadlock_con2'.
# Wait till the above SELECT stops.
set debug_sync='now WAIT_FOR parked';
# The below FLUSH TABLES WITH READ LOCK should acquire
# SNW locks on t1 and t2 and wait till SELECT closes t1.
# Sending:
flush tables t1, t2 with read lock;
# Switching to connection 'deadlock_con3'.
# Wait until FLUSH TABLES WITH t1, t2 READ LOCK starts waiting
# for SELECT to close t1.
# Resume SELECT, so it tries to acquire SW lock on t1 and blocks,
# creating a deadlock. This deadlock should be detected and resolved
# by backing-off SELECT. As a result FTWRL should be able to finish.
set debug_sync='now SIGNAL go';
# Switching to connection 'deadlock_con2'.
# Reap FLUSH TABLES WITH READ LOCK.
unlock tables;
# Switching to connection 'deadlock_con1'.
# Reap SELECT.
i
#
# The same scenario with a slightly different order of events
# which emphasizes that setting correct deadlock detector weights
# for flush waits is important.
#
set debug_sync= 'RESET';
# Switching to connection 'deadlock_con2'.
set debug_sync='flush_tables_with_read_lock_after_acquire_locks SIGNAL parked WAIT_FOR go';
# The below FLUSH TABLES WITH READ LOCK should acquire
# SNW locks on t1 and t2 and wait on debug sync point.
# Sending:
flush tables t1, t2 with read lock;
# Switching to connection 'deadlock_con1'.
# Wait till FLUSH TABLE WITH READ LOCK stops.
set debug_sync='now WAIT_FOR parked';
# Start statement which will acquire SR metadata lock on t1, open
# it and then will block while trying to acquire SW lock on t2.
# Sending:
select * from t1 where i in (select j from t2 for update);
# Switching to connection 'deadlock_con3'.
# Wait till the above SELECT blocks.
# Resume FLUSH TABLES, so it tries to flush t1, thus creating
# a deadlock. This deadlock should be detected and resolved by
# backing-off SELECT. As a result FTWRL should be able to finish.
set debug_sync='now SIGNAL go';
# Switching to connection 'deadlock_con2'.
# Reap FLUSH TABLES WITH READ LOCK.
unlock tables;
# Switching to connection 'deadlock_con1'.
# Reap SELECT.
i
#
# Now a more complex scenario involving two connections
# waiting for MDL and one for TDC.
#
set debug_sync= 'RESET';
# Switching to connection 'deadlock_con1'.
# Start a statement which will acquire SR metadata lock on t2, open it
# and then stop, before trying to acquire SR on t1 and opening it.
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
# Sending:
select * from t2, t1;
# Switching to connection 'deadlock_con2'.
# Wait till the above SELECT stops.
set debug_sync='now WAIT_FOR parked';
# The below FLUSH TABLES WITH READ LOCK should acquire
# SNW locks on t2 and wait till SELECT closes t2.
# Sending:
flush tables t2 with read lock;
# Switching to connection 'deadlock_con3'.
# Wait until FLUSH TABLES WITH READ LOCK starts waiting
# for SELECT to close t2.
# The below DROP TABLES should acquire X lock on t1 and start
# waiting for X lock on t2.
# Sending:
drop tables t1, t2;
# Switching to connection 'default'.
# Wait until DROP TABLES starts waiting for X lock on t2.
# Resume SELECT, so it tries to acquire SR lock on t1 and blocks,
# creating a deadlock. This deadlock should be detected and resolved
# by backing-off SELECT. As a result, FTWRL should be able to finish.
set debug_sync='now SIGNAL go';
# Switching to connection 'deadlock_con2'.
# Reap FLUSH TABLES WITH READ LOCK.
# Unblock DROP TABLES.
unlock tables;
# Switching to connection 'deadlock_con3'.
# Reap DROP TABLES.
# Switching to connection 'deadlock_con1'.
# Reap SELECT. It should emit error about missing table.
ERROR 42S02: Table 'test.t2' doesn't exist
# Switching to connection 'default'.
set debug_sync= 'RESET';
#
# Test for a scenario in which FLUSH TABLES <list> WITH READ LOCK
# used to erroneously release metadata locks.
#
drop tables if exists t1, t2;
set debug_sync= 'RESET';
create table t1(i int);
create table t2(j int);
# Switching to connection 'con2'.
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
# The below FLUSH TABLES <list> WITH READ LOCK should acquire
# SNW locks on t1 and t2, open table t1 and block on the debug
# sync point.
# Sending:
flush tables t1, t2 with read lock;
# Switching to connection 'con1'.
# Wait till FLUSH TABLES <list> WITH READ LOCK stops.
set debug_sync='now WAIT_FOR parked';
# Start a statement which will flush all tables and thus
# invalidate table t1 open by FLUSH TABLES <list> WITH READ LOCK.
# Sending:
flush tables;
# Switching to connection 'default'.
# Wait till the above FLUSH TABLES blocks.
# Resume FLUSH TABLES <list> WITH READ LOCK, so it tries to open t2
# discovers that its t1 is obsolete and tries to reopen all tables.
# Such reopen should not cause releasing of SNW metadata locks
# which would result in assertion failures.
set debug_sync='now SIGNAL go';
# Switching to connection 'con2'.
# Reap FLUSH TABLES <list> WITH READ LOCK.
unlock tables;
# Switching to connection 'con1'.
# Reap FLUSH TABLES.
# Clean-up.
# Switching to connection 'default'.
drop tables t1, t2;
set debug_sync= 'RESET';
#
# Test for bug #46748 "Assertion in MDL_context::wait_for_locks()

View File

@ -701,6 +701,7 @@ drop table t1,t2,t3,t4;
set query_cache_wlock_invalidate=1;
create table t1 (a int not null);
create table t2 (a int not null);
create view v1 as select * from t1;
select * from t1;
a
select * from t2;
@ -713,6 +714,17 @@ show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 1
unlock table;
select * from t1;
a
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 2
lock table v1 write;
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 2
unlock table;
drop view v1;
drop table t1,t2;
set query_cache_wlock_invalidate=default;
CREATE TABLE t1 (id INT PRIMARY KEY);
@ -853,7 +865,7 @@ Variable_name Value
Qcache_queries_in_cache 0
show status like "Qcache_inserts";
Variable_name Value
Qcache_inserts 18
Qcache_inserts 19
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 6
@ -866,7 +878,7 @@ Variable_name Value
Qcache_queries_in_cache 1
show status like "Qcache_inserts";
Variable_name Value
Qcache_inserts 19
Qcache_inserts 20
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 7

View File

@ -16,21 +16,19 @@ drop schema foo;
# Bug #48940 MDL deadlocks against mysql_rm_db
#
DROP SCHEMA IF EXISTS schema1;
DROP SCHEMA IF EXISTS schema2;
# Connection default
CREATE SCHEMA schema1;
CREATE SCHEMA schema2;
CREATE TABLE schema1.t1 (a INT);
SET autocommit= FALSE;
INSERT INTO schema1.t1 VALUES (1);
# Connection 2
DROP SCHEMA schema1;
# Connection default
ALTER SCHEMA schema2 DEFAULT CHARACTER SET utf8;
ALTER SCHEMA schema1 DEFAULT CHARACTER SET utf8;
Got one of the listed errors
SET autocommit= TRUE;
# Connection 2
# Connection default
DROP SCHEMA schema2;
#
# Bug #49988 MDL deadlocks with mysql_create_db, reload_acl_and_cache
#

View File

@ -148,12 +148,12 @@ f1()
# Sending 'drop procedure p1'...
drop procedure p1;
# --> connection con2
# Waitng for 'drop procedure t1' to get blocked on MDL lock...
# Waiting for 'drop procedure t1' to get blocked on MDL lock...
# Demonstrate that there is a pending exclusive lock.
# Sending 'select f1()'...
select f1();
# --> connection con3
# Waitng for 'select f1()' to get blocked by a pending MDL lock...
# Waiting for 'select f1()' to get blocked by a pending MDL lock...
# --> connection default
commit;
# --> connection con1
@ -174,12 +174,12 @@ f1()
# Sending 'create procedure p1'...
create procedure p1() begin end;
# --> connection con2
# Waitng for 'create procedure t1' to get blocked on MDL lock...
# Waiting for 'create procedure t1' to get blocked on MDL lock...
# Demonstrate that there is a pending exclusive lock.
# Sending 'select f1()'...
select f1();
# --> connection con3
# Waitng for 'select f1()' to get blocked by a pending MDL lock...
# Waiting for 'select f1()' to get blocked by a pending MDL lock...
# --> connection default
commit;
# --> connection con1
@ -200,12 +200,12 @@ f1()
# Sending 'alter procedure p1'...
alter procedure p1 contains sql;
# --> connection con2
# Waitng for 'alter procedure t1' to get blocked on MDL lock...
# Waiting for 'alter procedure t1' to get blocked on MDL lock...
# Demonstrate that there is a pending exclusive lock.
# Sending 'select f1()'...
select f1();
# --> connection con3
# Waitng for 'select f1()' to get blocked by a pending MDL lock...
# Waiting for 'select f1()' to get blocked by a pending MDL lock...
# --> connection default
commit;
# --> connection con1
@ -226,12 +226,12 @@ f1()
# Sending 'drop function f1'...
drop function f1;
# --> connection con2
# Waitng for 'drop function f1' to get blocked on MDL lock...
# Waiting for 'drop function f1' to get blocked on MDL lock...
# Demonstrate that there is a pending exclusive lock.
# Sending 'select f1()'...
select f1();
# --> connection con3
# Waitng for 'select f1()' to get blocked by a pending MDL lock...
# Waiting for 'select f1()' to get blocked by a pending MDL lock...
# --> connection default
commit;
# --> connection con1
@ -252,12 +252,12 @@ f1()
# Sending 'create function f1'...
create function f1() returns int return 2;
# --> connection con2
# Waitng for 'create function f1' to get blocked on MDL lock...
# Waiting for 'create function f1' to get blocked on MDL lock...
# Demonstrate that there is a pending exclusive lock.
# Sending 'select f1()'...
select f1();
# --> connection con3
# Waitng for 'select f1()' to get blocked by a pending MDL lock...
# Waiting for 'select f1()' to get blocked by a pending MDL lock...
# --> connection default
commit;
# --> connection con1
@ -279,12 +279,12 @@ f1()
# Sending 'alter function f1'...
alter function f1 contains sql;
# --> connection con2
# Waitng for 'alter function f1' to get blocked on MDL lock...
# Waiting for 'alter function f1' to get blocked on MDL lock...
# Demonstrate that there is a pending exclusive lock.
# Sending 'select f1()'...
select f1();
# --> connection con3
# Waitng for 'select f1()' to get blocked by a pending MDL lock...
# Waiting for 'select f1()' to get blocked by a pending MDL lock...
# --> connection default
commit;
# --> connection con1
@ -360,7 +360,7 @@ insert into t1 (a) values (1);
# Sending 'drop function f1'
drop function f1;
# --> connection con2
# Waitng for 'drop function f1' to get blocked on MDL lock...
# Waiting for 'drop function f1' to get blocked on MDL lock...
# --> connnection default
commit;
# --> connection con1
@ -379,7 +379,7 @@ a
# Sending 'drop function f1'
drop function f1;
# --> connection con2
# Waitng for 'drop function f1' to get blocked on MDL lock...
# Waiting for 'drop function f1' to get blocked on MDL lock...
# --> connnection default
commit;
# --> connection con1
@ -403,7 +403,7 @@ a
# Sending 'drop procedure p1'
drop procedure p1;
# --> connection con2
# Waitng for 'drop procedure p1' to get blocked on MDL lock...
# Waiting for 'drop procedure p1' to get blocked on MDL lock...
# --> connnection default
commit;
# --> connection con1
@ -424,7 +424,7 @@ insert into t1 (a) values (3);
# Sending 'drop function f2'
drop function f2;
# --> connection con2
# Waitng for 'drop function f2' to get blocked on MDL lock...
# Waiting for 'drop function f2' to get blocked on MDL lock...
# --> connnection default
commit;
# --> connection con1
@ -479,11 +479,11 @@ f2()
# Sending 'drop function f1'...
drop function f1;
# --> connection con2
# Waitng for 'drop function f1' to get blocked on MDL lock...
# Waiting for 'drop function f1' to get blocked on MDL lock...
# Sending 'drop function f2'...
drop function f2;
# --> connection default
# Waitng for 'drop function f2' to get blocked on MDL lock...
# Waiting for 'drop function f2' to get blocked on MDL lock...
rollback to savepoint sv;
# --> connection con2
# Reaping 'drop function f2'...
@ -537,10 +537,10 @@ f1()
# Sending 'alter function f1 ...'...
alter function f1 comment "comment";
# --> connection con2
# Waitng for 'alter function f1 ...' to get blocked on MDL lock...
# Waiting for 'alter function f1 ...' to get blocked on MDL lock...
# Sending 'call p1()'...
call p1();
# Waitng for 'call p1()' to get blocked on MDL lock on f1...
# Waiting for 'call p1()' to get blocked on MDL lock on f1...
# Let 'alter function f1 ...' go through...
commit;
# --> connection con1
@ -573,7 +573,7 @@ f1()
# Sending 'alter function f1 ...'...
alter function f1 comment "comment";
# --> connection con2
# Waitng for 'alter function f1 ...' to get blocked on MDL lock...
# Waiting for 'alter function f1 ...' to get blocked on MDL lock...
#
# We just mention p1() in the body of f2() to make
# sure that p1() is prelocked for f2().
@ -595,7 +595,7 @@ select f2() into @var;
end|
# Sending 'call p1()'...
call p1();
# Waitng for 'call p1()' to get blocked on MDL lock on f1...
# Waiting for 'call p1()' to get blocked on MDL lock on f1...
# Let 'alter function f1 ...' go through...
commit;
# --> connection con1
@ -634,7 +634,7 @@ get_lock("30977", 0)
# Sending 'select f3()'...
select f3();
# --> connection con1
# Waitng for 'select f3()' to get blocked on the user level lock...
# Waiting for 'select f3()' to get blocked on the user level lock...
# Do something to change the cache version.
create function f4() returns int return 4;
drop function f4;

View File

@ -35,7 +35,7 @@ call bug9486();
show processlist;
Id User Host db Command Time State Info
# root localhost test Sleep # NULL
# root localhost test Query # Waiting for table update t1, t2 set val= 1 where id1=id2
# root localhost test Query # Waiting for table metadata lock update t1, t2 set val= 1 where id1=id2
# root localhost test Query # NULL show processlist
# root localhost test Sleep # NULL
unlock tables;

View File

@ -60,7 +60,7 @@ let $wait_condition=
--echo # con1
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE
state = "Table lock" and info = "INSERT INTO t2 VALUES (3)";
state = "Waiting for table level lock" and info = "INSERT INTO t2 VALUES (3)";
--source include/wait_condition.inc
SELECT RELEASE_LOCK('Bug#34306');
--connection con2

View File

@ -367,14 +367,14 @@ echo
;
connection default;
echo
# Poll till INFO is no more NULL and State = 'Waiting for table'.
# Poll till INFO is no more NULL and State = 'Waiting for table metadata lock'.
;
let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE INFO IS NOT NULL AND STATE = 'Waiting for table';
WHERE INFO IS NOT NULL AND STATE = 'Waiting for table metadata lock';
--source include/wait_condition.inc
#
# Expect to see the state 'Waiting for table' for the third connection because the SELECT
# collides with the WRITE TABLE LOCK.
# Expect to see the state 'Waiting for table metadata lock' for the third
# connection because the SELECT collides with the WRITE TABLE LOCK.
--replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
UNLOCK TABLES;
@ -422,10 +422,10 @@ echo
;
connection default;
echo
# Poll till INFO is no more NULL and State = 'Waiting for table'.
# Poll till INFO is no more NULL and State = 'Waiting for table metadata lock'.
;
let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE INFO IS NOT NULL AND STATE = 'Waiting for table';
WHERE INFO IS NOT NULL AND STATE = 'Waiting for table metadata lock';
--source include/wait_condition.inc
echo
# Expect result:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -87,7 +87,8 @@ connection con1;
--echo # Wait until LOCK TABLE is blocked on SQL-level lock.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "lock table t1 write";
where state = "Waiting for table metadata lock" and
info = "lock table t1 write";
--source include/wait_condition.inc
--echo # We should be able to do UPDATEs and SELECTs within transaction.
update t1 set x=1 where id = 0;

View File

@ -28,7 +28,8 @@ ALTER TABLE t1 TRUNCATE PARTITION pMax;
--echo # con default
let $wait_condition=
SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE STATE = "Waiting for table" AND INFO = "ALTER TABLE t1 TRUNCATE PARTITION pMax";
WHERE STATE = "Waiting for table metadata lock" AND
INFO = "ALTER TABLE t1 TRUNCATE PARTITION pMax";
--source include/wait_condition.inc
--sorted_result
SELECT * FROM t1;

View File

@ -40,12 +40,12 @@ wait/synch/cond/sql/COND_flush_thread_cache YES YES
wait/synch/cond/sql/COND_global_read_lock YES YES
wait/synch/cond/sql/COND_manager YES YES
wait/synch/cond/sql/COND_queue_state YES YES
wait/synch/cond/sql/COND_refresh YES YES
wait/synch/cond/sql/COND_rpl_status YES YES
wait/synch/cond/sql/COND_server_started YES YES
wait/synch/cond/sql/COND_thread_cache YES YES
wait/synch/cond/sql/COND_thread_count YES YES
wait/synch/cond/sql/Delayed_insert::cond YES YES
wait/synch/cond/sql/Delayed_insert::cond_client YES YES
select * from performance_schema.SETUP_INSTRUMENTS
where name='Wait';
select * from performance_schema.SETUP_INSTRUMENTS

View File

@ -182,7 +182,7 @@ count(name)
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_refresh";
count(name)
1
0
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_thread_count";
count(name)

View File

@ -30,7 +30,7 @@ connection master1;
connection master;
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table" AND info = "DROP TABLE tt";
WHERE state = "Waiting for table metadata lock" AND info = "DROP TABLE tt";
--source include/wait_condition.inc
ROLLBACK TO SAVEPOINT insert_statement;
COMMIT;

View File

@ -655,7 +655,8 @@ connection master;
connection master1;
--echo # Waitng for 'insert into t1 ...' to get blocked on table lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='insert into t1 (a) values (f1())';
where state='Waiting for table metadata lock' and
info='insert into t1 (a) values (f1())';
--source include/wait_condition.inc
--echo # Sending 'drop function f1'. It will wait till insert finishes.
--send drop function f1;
@ -663,7 +664,7 @@ where state='Waiting for table' and info='insert into t1 (a) values (f1())';
connection default;
--echo # Check that 'drop function f1' gets blocked.
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f1';
where state='Waiting for stored function metadata lock' and info='drop function f1';
--source include/wait_condition.inc
--echo # Now let's let 'insert' go through...
unlock tables;

View File

@ -56,7 +56,7 @@ let $wait_condition=
connection master;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "drop view v1";
where state = "Waiting for table metadata lock" and info = "drop view v1";
--source include/wait_condition.inc
select release_lock("lock_bg25144");
@ -106,7 +106,7 @@ let $wait_condition=
connection master;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "alter view v1 as select * from t2";
--source include/wait_condition.inc

View File

@ -10,8 +10,6 @@
#
##############################################################################
rpl_ndb_stm_innodb : Bug#54850 2010-07-02 alik rpl_ndb.rpl_ndb_stm_innodb and rpl_ndb.rpl_ndb_2other fails
rpl_ndb_2other : Bug#54850 2010-07-02 alik rpl_ndb.rpl_ndb_stm_innodb and rpl_ndb.rpl_ndb_2other fails
rpl_ndb_row_implicit_commit_binlog : Bug#55849 2010-08-09 alik rpl_ndb.rpl_ndb_row_implicit_commit_binlog fails
# the below testcase have been reworked to avoid the bug, test contains comment, keep bug open

View File

@ -1 +1 @@
--innodb --loose-ndbcluster=OFF --log-slave-updates=0
--innodb --loose-ndbcluster=OFF --log-slave-updates=0 --default-storage-engine=MyISAM

View File

@ -0,0 +1 @@
--default-storage-engine=MyISAM

View File

@ -37,9 +37,9 @@ INSERT INTO t1(name) VALUES('Record_7');
connection default;
## show processlist info and state ##
SELECT state,info FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE state= "Table lock" AND info LIKE "INSERT INTO t1%";
WHERE state= "Waiting for table level lock" AND info LIKE "INSERT INTO t1%";
state info
Table lock INSERT INTO t1(name) VALUES('Record_7')
Waiting for table level lock INSERT INTO t1(name) VALUES('Record_7')
## table contents befor UNLOCK ##
SELECT * FROM t1;
name

View File

@ -11,7 +11,6 @@ CREATE TABLE t1(id int, value varchar(10));
INSERT INTO t1 VALUES(1, 'val1');
INSERT INTO t1 VALUES(2, 'val2');
INSERT INTO t1 VALUES(3, 'val3');
CREATE VIEW v1 AS SELECT * FROM t1;
SET GLOBAL query_cache_size = 131072;
FLUSHING CACHE
SET GLOBAL query_cache_size = 0;
@ -33,11 +32,11 @@ SHOW STATUS LIKE 'Qcache_queries_in_cache';
Variable_name Value
Qcache_queries_in_cache 1
1 Expected
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
UNLOCK TABLES;
SHOW STATUS LIKE 'Qcache_queries_in_cache';
Variable_name Value
Qcache_queries_in_cache 1
Qcache_queries_in_cache 0
0 Expected
'#----------------------------FN_DYNVARS_136_02-----------------------#'
SELECT * FROM t1;
@ -49,13 +48,12 @@ id value
2 val2
3 val3
** Connection con0 **
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
** Connection con1 **
** Asynchronous Execution **
SELECT * FROM t1;
** Connection con0 **
wait until table is locked
Timeout in wait_condition.inc for SELECT count(*) > 0 FROM information_schema.processlist WHERE state= 'Table lock'
UNLOCK TABLES;
** Connection con1 **
** Asynchronous Result **
@ -79,7 +77,7 @@ SHOW STATUS LIKE 'Qcache_queries_in_cache';
Variable_name Value
Qcache_queries_in_cache 1
1 Expected
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
UNLOCK TABLES;
SHOW STATUS LIKE 'Qcache_queries_in_cache';
Variable_name Value
@ -102,7 +100,7 @@ id value
2 val2
3 val3
** Connection con0 **
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
** Connection con1 **
** Should not be blocked **
SELECT * FROM t1;
@ -165,4 +163,3 @@ SET @@GLOBAL.query_cache_type = @old_cache_type;
** Connection default **
Disconnecting Connections con0, con1
DROP TABLE t1;
DROP VIEW v1;

View File

@ -98,12 +98,13 @@ INSERT INTO t1(name) VALUES('Record_7');
connection default;
# wait until INSERT will be locked (low performance)
let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE state= "Table lock" AND info LIKE "INSERT INTO t1%";
WHERE state= "Waiting for table level lock" AND
info LIKE "INSERT INTO t1%";
--source include/wait_condition.inc
--echo ## show processlist info and state ##
SELECT state,info FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE state= "Table lock" AND info LIKE "INSERT INTO t1%";
WHERE state= "Waiting for table level lock" AND info LIKE "INSERT INTO t1%";
--echo ## table contents befor UNLOCK ##
SELECT * FROM t1;
UNLOCK TABLES;

View File

@ -123,7 +123,7 @@ connection default;
--echo ** Wait till con0 is blocked **
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = 'Table lock' AND info = '$my_select';
WHERE state = 'Waiting for table level lock' AND info = '$my_select';
--source include/wait_condition.inc
UNLOCK TABLES;
@ -219,7 +219,7 @@ connection default;
--echo ** Wait till con0 is blocked **
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = 'Table lock' AND info = '$my_select';
WHERE state = 'Waiting for table level lock' AND info = '$my_select';
--source include/wait_condition.inc
UNLOCK TABLES;

View File

@ -60,8 +60,6 @@ INSERT INTO t1 VALUES(1, 'val1');
INSERT INTO t1 VALUES(2, 'val2');
INSERT INTO t1 VALUES(3, 'val3');
CREATE VIEW v1 AS SELECT * FROM t1;
#
# Clearing the query cache and setting up cache size
#
@ -101,7 +99,7 @@ SELECT * FROM t1;
SHOW STATUS LIKE 'Qcache_queries_in_cache';
--echo 1 Expected
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
UNLOCK TABLES;
@ -129,7 +127,7 @@ SELECT * FROM t1;
--echo ** Connection con0 **
connection con0;
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
--echo ** Connection con1 **
connection con1;
@ -141,7 +139,8 @@ send SELECT * FROM t1;
connection con0;
--echo wait until table is locked
let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE state= 'Table lock';
let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist
WHERE state= 'Waiting for table metadata lock';
--source include/wait_condition.inc
UNLOCK TABLES;
@ -177,7 +176,7 @@ SELECT * FROM t1;
SHOW STATUS LIKE 'Qcache_queries_in_cache';
--echo 1 Expected
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
UNLOCK TABLES;
@ -201,7 +200,7 @@ SELECT * FROM t1;
--echo ** Connection con0 **
connection con0;
LOCK TABLE v1 WRITE;
LOCK TABLE t1 WRITE;
--echo ** Connection con1 **
connection con1;
@ -283,7 +282,6 @@ disconnect con0;
disconnect con1;
DROP TABLE t1;
DROP VIEW v1;
--enable_ps_protocol

View File

@ -86,7 +86,9 @@ delimiter ;|
--echo ** Connection con0 **
connection con0;
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state='Table lock' AND info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist
WHERE state='Waiting for table level lock' AND
info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
--source include/wait_condition.inc
--echo ** Asynchronous Execution **
@ -102,7 +104,8 @@ delimiter ;|
--echo ** Connection default **
connection default;
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist WHERE state LIKE 'Table lock';
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist
WHERE state LIKE 'Waiting for table level lock';
--source include/wait_condition.inc
UNLOCK TABLES;
@ -157,7 +160,9 @@ delimiter ;|
--echo ** Connection con0 **
connection con0;
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state='Table lock' AND info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist
WHERE state='Waiting for table level lock' AND
info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
--source include/wait_condition.inc
--echo ** Asynchronous Execution **
@ -173,7 +178,8 @@ delimiter ;|
--echo ** Connection default **
connection default;
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist WHERE state LIKE 'Table lock';
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist
WHERE state LIKE 'Waiting for table level lock';
--source include/wait_condition.inc
UNLOCK TABLES;

View File

@ -1,4 +1,3 @@
--source include/have_thread_concurrency.inc
#
# only global
#

View File

@ -307,7 +307,7 @@ connection update;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where command = "Delayed insert" and state = "Table lock";
where command = "Delayed insert" and state = "Waiting for table level lock";
--source include/wait_condition.inc
connect (select,localhost,root,,);
--echo connection: select

View File

@ -19,3 +19,4 @@ plugin_load : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
plugin_not_embedded : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically
sp_sync : Bug#48157 2010-02-06 5.5-m3 demands a differnt solution
ctype_utf8mb4_ndb : Bug#55799, Bug#51907, disabled by Konstantin 2010-08-06

View File

@ -121,3 +121,28 @@ let $wait_condition=
drop database events_test;
--echo #
--echo # Bug#54105 assert in MDL_context::release_locks_stored_before
--echo #
USE test;
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
DROP EVENT IF EXISTS e1;
--enable_warnings
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
CREATE TABLE t2 (a INT);
CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY DO SELECT 1;
START TRANSACTION;
INSERT INTO t1 VALUES (1);
SAVEPOINT A;
--replace_regex /STARTS '[^']+'/STARTS '#'/
SHOW CREATE EVENT e1;
SELECT * FROM t2;
ROLLBACK WORK TO SAVEPOINT A;
DROP TABLE t1, t2;

View File

@ -318,6 +318,58 @@ insert into t2 (a) values (3);
--echo # --> connection default;
connection default;
unlock tables;
--echo #
--echo # Check that "FLUSH TABLES <list> WITH READ LOCK" is
--echo # compatible with active "FLUSH TABLES WITH READ LOCK".
--echo # Vice versa it is not true, since tables read-locked by
--echo # "FLUSH TABLES <list> WITH READ LOCK" can't be flushed.
flush tables with read lock;
--echo # --> connection con1;
connection con1;
flush table t1 with read lock;
select * from t1;
unlock tables;
--echo # --> connection default;
connection default;
unlock tables;
--echo #
--echo # Check that FLUSH TABLES t1 WITH READ LOCK
--echo # does not conflict with an existing FLUSH TABLES t2
--echo # WITH READ LOCK.
--echo #
flush table t1 with read lock;
--echo # --> connection con1
connection con1;
flush table t2 with read lock;
unlock tables;
--echo # --> connection default
connection default;
unlock tables;
--echo #
--echo # Check that FLUSH TABLES t1 WITH READ LOCK
--echo # does not conflict with SET GLOBAL read_only=1.
--echo #
set global read_only=1;
--echo # connection con1
connection con1;
flush table t1 with read lock;
unlock tables;
--echo # connection default
connection default;
set global read_only=0;
--echo #
--echo # Check that it's possible to read-lock
--echo # tables locked with FLUSH TABLE <list> WITH READ LOCK.
--echo #
flush tables t1, t2 with read lock;
--echo # connection con1
connection con1;
lock table t1 read, t2 read;
unlock tables;
--echo # connection default
connection default;
unlock tables;
--echo # --> connection con1
connection con1;
disconnect con1;
@ -355,3 +407,142 @@ drop temporary table v1;
unlock tables;
drop view v2, v3;
drop table t1, v1;
--echo #
--echo # FLUSH TABLES <list> WITH READ LOCK and HANDLER
--echo #
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (a int, key a (a));
insert into t1 (a) values (1), (2), (3);
handler t1 open;
handler t1 read a next;
handler t1 read a next;
flush tables t1 with read lock;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
handler t1 read a next;
unlock tables;
--echo #
--echo # Sic: lost handler position.
--echo #
handler t1 read a next;
handler t1 close;
drop table t1;
--echo #
--echo # Bug#52117 Pending FLUSH TALBES <list> aborts
--echo # transactions unnecessarily.
--echo #
--disable_warnings
drop table if exists t1;
--enable_warnings
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
--echo # --> conection default
connection default;
create table t1 (a int);
begin;
select * from t1;
--echo # --> connection con1
connection con1;
--echo #
--echo # Issue a LOCK TABLE t1 READ. We could use HANDLER t1 OPEN
--echo # or a long-running select -- anything that
--echo # prevents FLUSH TABLE t1 from immediate completion would do.
--echo #
lock table t1 read;
--echo # --> connection con2
connection con2;
--echo #
--echo # FLUSH TABLE expels the table definition from the cache.
--echo # Sending 'flush table t1'...
send flush table t1;
--echo # --> connection default
connection default;
--echo # Let flush table sync in.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table flush"
and info = "flush table t1";
--source include/wait_condition.inc
send select * from t1;
--echo # --> connection con1
connection con1;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table flush"
and info = "select * from t1";
select * from t1;
unlock tables;
--echo # --> connection con2
connection con2;
--echo # Reaping 'flush table t1'...
reap;
--echo # --> connection default
connection default;
--echo # Reaping 'select * from t1'...
reap;
commit;
--echo #
--echo # Repeat the same test but with FLUSH TABLES
--echo #
begin;
select * from t1;
--echo # --> connection con1
connection con1;
--echo #
--echo # Issue a LOCK TABLE t1 READ.
--echo #
lock table t1 read;
--echo # --> connection con2
connection con2;
--echo #
--echo # FLUSH TABLES expels the table definition from the cache.
--echo # Sending 'flush tables'...
send flush tables;
--echo # --> connection default
connection default;
--echo # Let flush table sync in.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table flush"
and info = "flush tables";
--source include/wait_condition.inc
send select * from t1;
--echo # --> connection con1
connection con1;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table flush"
and info = "select * from t1";
select * from t1;
unlock tables;
--echo # --> connection con2
connection con2;
--echo # Reaping 'flush tables'...
reap;
--echo # --> connection default
connection default;
--echo # Reaping 'select * from t1'...
reap;
commit;
--echo # Cleanup
--echo # --> connection con1
connection con1;
disconnect con1;
--source include/wait_until_disconnected.inc
--echo # --> connection con2
connection con2;
disconnect con2;
--source include/wait_until_disconnected.inc
--echo # --> connection default
connection default;
drop table t1;

View File

@ -1470,7 +1470,8 @@ connection con3726_2;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info like "rename table t2 to t3";
where state = "Waiting for table metadata lock" and
info like "rename table t2 to t3";
--source include/wait_condition.inc
--echo # These statements should not be blocked by pending lock requests
select table_name, column_name, data_type from information_schema.columns

View File

@ -89,3 +89,23 @@ from information_schema.referential_constraints
where constraint_schema = schema();
drop table t2;
set foreign_key_checks = 1;
--echo #
--echo # Bug#55973 Assertion `thd->transaction.stmt.is_empty()'
--echo # on CREATE TABLE .. SELECT I_S.PART
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
--enable_warnings
CREATE VIEW v1 AS SELECT 1;
# This used to case an assert.
CREATE TABLE t1 engine = InnoDB AS
SELECT * FROM information_schema.partitions
WHERE table_schema= 'test' AND table_name= 'v1';
DROP TABLE t1;
DROP VIEW v1;

View File

@ -42,7 +42,7 @@ let $wait_condition=
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE info = "DROP TABLE t1" and
state = "Waiting for table";
state = "Waiting for table metadata lock";
--source include/wait_condition.inc
--echo # Connection 1 is now holding the lock.
--echo # Issuing insert from connection 1 while connection 2&3
@ -97,7 +97,8 @@ connection default;
--echo # connection holds SW metadata lock on table to be altered.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 add column c4 int";
where state = "Waiting for table metadata lock" and
info = "alter table t1 add column c4 int";
--source include/wait_condition.inc
--echo # The below statement should succeed. It should not
@ -196,7 +197,7 @@ connection default;
--echo # Connection con1
connection con1;
let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for table' AND info='OPTIMIZE TABLE t1';
WHERE state='Waiting for table metadata lock' AND info='OPTIMIZE TABLE t1';
--source include/wait_condition.inc
SELECT * FROM t1;
COMMIT;
@ -241,7 +242,7 @@ connection con2;
--echo # Waiting for 'SELECT * FROM v1' to sync in.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table" AND info = "SELECT * FROM v1";
WHERE state = "Waiting for table metadata lock" AND info = "SELECT * FROM v1";
--source include/wait_condition.inc
# This should block due to v1 being locked.
--echo # Sending:
@ -252,7 +253,8 @@ connection con3;
--echo # Waiting for 'ALTER VIEW v1 AS SELECT 2 FROM t2' to sync in.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table" AND info = "ALTER VIEW v1 AS SELECT 2 FROM t2";
WHERE state = "Waiting for table metadata lock" AND
info = "ALTER VIEW v1 AS SELECT 2 FROM t2";
--source include/wait_condition.inc
# Unlock t1 allowing SELECT * FROM v1 to proceed.
UNLOCK TABLES;

View File

@ -799,8 +799,9 @@ connection default;
--echo # table as it acquires LOCK_S locks on rows of old version, which
--echo # are compatible with locks acquired by connection 'con1'.
let $wait_condition=
select count(*) = 1 from information_schema.processlist where state =
"Waiting for table" and info = "alter table t1 add column j int";
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table metadata lock" and
info = "alter table t1 add column j int";
--source include/wait_condition.inc
--echo # The below statement will deadlock because it will try to acquire
@ -844,7 +845,8 @@ connection default;
--echo # Wait until ALTER is blocked because of active SR lock.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 rebuild partition p0";
where state = "Waiting for table metadata lock" and
info = "alter table t1 rebuild partition p0";
--source include/wait_condition.inc
--echo # The below statement should succeed as transaction

View File

@ -174,7 +174,7 @@ connection default;
# we must wait till the insert opens and locks the table
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and id = $ID;
where state = "Waiting for table level lock" and id = $ID;
--source include/wait_condition.inc
connect (select,localhost,root,,);
--echo connection: select

View File

@ -357,7 +357,8 @@ let $ID= `select connection_id()`;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "rename table t1 to t2";
where state = "Waiting for table metadata lock" and
info = "rename table t1 to t2";
--source include/wait_condition.inc
--replace_result $ID ID
eval kill query $ID;
@ -372,7 +373,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "drop table t1";
--source include/wait_condition.inc
--replace_result $ID ID
@ -388,7 +389,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "create trigger t1_bi before insert on t1 for each row set @a:=1";
--source include/wait_condition.inc
--replace_result $ID ID
@ -407,7 +408,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "alter table t1 add column j int";
--source include/wait_condition.inc
--replace_result $ID ID
@ -423,7 +424,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "alter table t1 rename to t2";
--source include/wait_condition.inc
--replace_result $ID ID
@ -437,7 +438,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "alter table t1 disable keys";
--source include/wait_condition.inc
--replace_result $ID ID
@ -452,7 +453,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "alter table t1 alter column i set default 100";
--source include/wait_condition.inc
--replace_result $ID ID
@ -474,7 +475,7 @@ connection ddl;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "alter table t2 alter column i set default 100";
--source include/wait_condition.inc
--replace_result $ID ID
@ -499,7 +500,7 @@ connection ddl;
connection dml;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "rename tables t1 to t3, t2 to t1";
--source include/wait_condition.inc
let $ID2= `select connection_id()`;
@ -508,7 +509,7 @@ let $ID2= `select connection_id()`;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table metadata lock" and
info = "insert into t2 values (1)";
--source include/wait_condition.inc
--replace_result $ID2 ID2
@ -536,7 +537,7 @@ connection ddl;
connection dml;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Flushing tables" and
where state = "Waiting for table flush" and
info = "flush tables";
--source include/wait_condition.inc
--send select * from t1
@ -544,7 +545,7 @@ let $wait_condition=
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
where state = "Waiting for table flush" and
info = "select * from t1";
--source include/wait_condition.inc
--replace_result $ID2 ID2

View File

@ -32,7 +32,8 @@ connection reader;
# Sleep a bit till the update of connection writer is in work and hangs
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "update low_priority t1 set n = 4";
where state = "Waiting for table level lock" and
info = "update low_priority t1 set n = 4";
--source include/wait_condition.inc
send
select n from t1;
@ -40,7 +41,8 @@ connection locker2;
# Sleep a bit till the select of connection reader is in work and hangs
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "select n from t1";
where state = "Waiting for table level lock" and
info = "select n from t1";
--source include/wait_condition.inc
select release_lock("mysqltest_lock");
connection locker;
@ -72,7 +74,8 @@ connection reader;
# Sleep a bit till the update of connection writer is in work and hangs
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "update low_priority t1 set n = 4";
where state = "Waiting for table level lock" and
info = "update low_priority t1 set n = 4";
--source include/wait_condition.inc
select n from t1;
connection locker2;
@ -120,7 +123,8 @@ insert t1 select * from t2;
connection locker;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "insert t1 select * from t2";
where state = "Waiting for table metadata lock" and
info = "insert t1 select * from t2";
--source include/wait_condition.inc
drop table t2;
unlock tables;
@ -145,7 +149,8 @@ connection locker;
# Sleep a bit till the insert of connection reader is in work and hangs
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "insert t1 select * from t2";
where state = "Waiting for table metadata lock" and
info = "insert t1 select * from t2";
--source include/wait_condition.inc
drop table t2;
unlock tables;
@ -191,7 +196,7 @@ connection locker;
# Sleep a bit till the select of connection reader is in work and hangs
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table" AND info =
WHERE state = "Waiting for table metadata lock" AND info =
"SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1";
--source include/wait_condition.inc
# Make test case independent from earlier grants.
@ -223,7 +228,8 @@ connection writer;
# Sleep a bit till the flush of connection locker is in work and hangs
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "FLUSH TABLES WITH READ LOCK";
where state = "Waiting for global metadata lock" and
info = "FLUSH TABLES WITH READ LOCK";
--source include/wait_condition.inc
# This must not block.
--error ER_TABLE_NOT_LOCKED
@ -254,7 +260,8 @@ connection writer;
# Sleep a bit till the flush of connection locker is in work and hangs
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "FLUSH TABLES WITH READ LOCK";
where state = "Waiting for global metadata lock" and
info = "FLUSH TABLES WITH READ LOCK";
--source include/wait_condition.inc
--error ER_TABLE_NOT_LOCKED
CREATE TABLE t2 AS SELECT * FROM t1;
@ -326,7 +333,8 @@ connection reader;
# Wait till connection writer is blocked
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 auto_increment=0";
where state = "Waiting for table metadata lock" and
info = "alter table t1 auto_increment=0";
--source include/wait_condition.inc
send
alter table t1 auto_increment=0;
@ -334,7 +342,8 @@ connection locker;
# Wait till connection reader is blocked
let $wait_condition=
select count(*) = 2 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 auto_increment=0";
where state = "Waiting for table metadata lock" and
info = "alter table t1 auto_increment=0";
--source include/wait_condition.inc
unlock tables;
connection writer;
@ -367,7 +376,8 @@ connection con5;
--echo # con5
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "flush tables with read lock";
where state = "Waiting for global metadata lock" and
info = "flush tables with read lock";
--source include/wait_condition.inc
--echo # global read lock is taken
connection con3;
@ -489,16 +499,20 @@ update t1 set i= 10;
connection reader;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "update t1 set i= 10";
where state = "Waiting for table level lock" and
info = "update t1 set i= 10";
--source include/wait_condition.inc
send
select * from t1;
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "select * from t1";
where state = "Waiting for table level lock" and
info = "select * from t1";
--source include/wait_condition.inc
let $ID= `select id from information_schema.processlist where state = "Table lock" and info = "update t1 set i= 10"`;
let $ID= `select id from information_schema.processlist
where state = "Waiting for table level lock" and
info = "update t1 set i= 10"`;
--replace_result $ID ID
eval kill query $ID;
connection reader;
@ -557,7 +571,7 @@ connection default;
--echo connection: default
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
alter table t1 add column j int;
connect (insert,localhost,root,,test,,);
@ -565,7 +579,7 @@ connection insert;
--echo connection: insert
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
--send insert into t1 values (1,2);
--echo connection: default
@ -615,12 +629,12 @@ connection default;
--echo connection: default
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
flush tables;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
unlock tables;
connection flush;
@ -646,7 +660,8 @@ send insert into t1 values(1);
connection default;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "insert into t1 values(1)";
where state = "Waiting for table level lock" and
info = "insert into t1 values(1)";
--source include/wait_condition.inc
let $tlwb= `show status like 'Table_locks_waited'`;
unlock tables;
@ -683,12 +698,12 @@ connection default;
--echo connection: default
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
flush tables;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
drop table t1;
connection flush;
@ -725,7 +740,8 @@ connection default;
--echo # connection holds SW metadata lock on table to be altered.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 add column c4 int";
where state = "Waiting for table metadata lock" and
info = "alter table t1 add column c4 int";
--source include/wait_condition.inc
--echo # The below statement should succeed. It should not
@ -825,7 +841,8 @@ connection default;
--echo # Wait until ALTER TABLE gets blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 add column j int";
where state = "Waiting for table metadata lock" and
info = "alter table t1 add column j int";
--source include/wait_condition.inc
--echo # The below statement should try to acquire SW lock on 't1'
--echo # and therefore should get ER_LOCK_DEADLOCK error. Before
@ -855,7 +872,8 @@ connection default;
--echo # Wait until ALTER TABLE gets blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "alter table t1 drop column j";
where state = "Waiting for table metadata lock" and
info = "alter table t1 drop column j";
--source include/wait_condition.inc
--echo # The below statement should try to acquire SW lock on 't1'
--echo # and therefore should get ER_LOCK_DEADLOCK error. Before
@ -982,7 +1000,7 @@ connection con3;
connection con2;
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Flushing tables" AND info = "FLUSH TABLES";
WHERE state = "Waiting for table flush" AND info = "FLUSH TABLES";
--source include/wait_condition.inc
--error ER_LOCK_WAIT_TIMEOUT
SELECT * FROM t1;
@ -1014,7 +1032,8 @@ connection con3;
connection con2;
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table" AND info = "DROP TABLE t1, t2";
WHERE state = "Waiting for table metadata lock" AND
info = "DROP TABLE t1, t2";
--source include/wait_condition.inc
# Note: This query causes two timeouts.
# 1: try_acquire_high_prio_shared_mdl_lock on t1
@ -1069,7 +1088,8 @@ connection default;
--echo # Wait until RENAME TABLE is blocked on table 't3'.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "rename tables t1 to t2, t2 to t3";
where state = "Waiting for table metadata lock" and
info = "rename tables t1 to t2, t2 to t3";
--source include/wait_condition.inc
--echo # Kill RENAME TABLE.
--replace_result $ID ID

View File

@ -898,7 +898,7 @@ set debug_sync= 'now WAIT_FOR parked';
connection default;
--echo # Wait until this LOCK TABLES statement starts waiting for table lock.
let $wait_condition= select count(*)= 1 from information_schema.processlist
where state= 'Table lock' and
where state= 'Waiting for table level lock' and
info='lock table v1 write';
--source include/wait_condition.inc
--echo # Allow SELECT ... FOR UPDATE to resume.
@ -972,7 +972,7 @@ connection default;
connection con2;
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table"
WHERE state = "Waiting for table metadata lock"
AND info = "ALTER TABLE t1 ADD COLUMN j INT";
--source include/wait_condition.inc

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ connection default;
#--sleep 8
#SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE ID = $con1_id AND STATE = 'Waiting for table';
WHERE ID = $con1_id AND STATE = 'Waiting for table metadata lock';
--source include/wait_condition.inc
#SELECT NOW();
--echo # Kick INSERT out of thr_multi_lock().
@ -61,7 +61,7 @@ FLUSH TABLES;
#--sleep 8
#SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE ID = $con1_id AND STATE = 'Waiting for table';
WHERE ID = $con1_id AND STATE = 'Waiting for table metadata lock';
--source include/wait_condition.inc
#SELECT NOW();
--echo # Unlock and close table and wait for con1 to close too.

View File

@ -497,7 +497,7 @@ connection updater;
# Wait till "alter table t1 ..." of session changer is in work.
# = There is one session waiting.
let $wait_condition= select count(*)= 1 from information_schema.processlist
where state= 'Waiting for table';
where state= 'Waiting for table metadata lock';
--source include/wait_condition.inc
send update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a;
@ -508,7 +508,7 @@ connection locker;
# are in work.
# = There are two session waiting.
let $wait_condition= select count(*)= 2 from information_schema.processlist
where state= 'Waiting for table';
where state= 'Waiting for table metadata lock';
--source include/wait_condition.inc
unlock tables;

View File

@ -498,12 +498,20 @@ drop table t1,t2,t3,t4;
set query_cache_wlock_invalidate=1;
create table t1 (a int not null);
create table t2 (a int not null);
create view v1 as select * from t1;
select * from t1;
select * from t2;
show status like "Qcache_queries_in_cache";
lock table t1 write, t2 read;
show status like "Qcache_queries_in_cache";
unlock table;
select * from t1;
# Implicit locking of t1 does not invalidate QC
show status like "Qcache_queries_in_cache";
lock table v1 write;
show status like "Qcache_queries_in_cache";
unlock table;
drop view v1;
drop table t1,t2;
set query_cache_wlock_invalidate=default;

View File

@ -58,18 +58,18 @@ connection user3;
# Typical information_schema.processlist content after sufficient sleep time
# ID USER COMMAND TIME STATE INFO
# ....
# 2 root Query 5 Table lock SELECT *, (SELECT COUNT(*) FROM t2) FROM t1
# 2 root Query 5 Waiting for table level lock SELECT *, (SELECT COUNT(*) FROM t2) FROM t1
# ....
# XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# The values marked with 'X' must be reached.
--echo # Poll till the select of connection user1 is blocked by the write lock on t1.
let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = 'Table lock'
WHERE state = 'Waiting for table level lock'
AND info = '$select_for_qc';
--source include/wait_condition.inc
eval
SELECT user,command,state,info FROM information_schema.processlist
WHERE state = 'Table lock'
WHERE state = 'Waiting for table level lock'
AND info = '$select_for_qc';
INSERT INTO t1 VALUES (4);

View File

@ -23,7 +23,6 @@ drop schema foo;
--disable_warnings
DROP SCHEMA IF EXISTS schema1;
DROP SCHEMA IF EXISTS schema2;
--enable_warnings
connect(con2, localhost, root);
@ -32,7 +31,6 @@ connect(con2, localhost, root);
connection default;
CREATE SCHEMA schema1;
CREATE SCHEMA schema2;
CREATE TABLE schema1.t1 (a INT);
SET autocommit= FALSE;
@ -45,10 +43,13 @@ connection con2;
--echo # Connection default
connection default;
let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
WHERE state= 'Waiting for table'
WHERE state= 'Waiting for table metadata lock'
AND info='DROP SCHEMA schema1';
--source include/wait_condition.inc
ALTER SCHEMA schema2 DEFAULT CHARACTER SET utf8;
# Error 1 is from ALTER DATABASE when the database does not exist.
# Listing the error twice to prevent result diffences based on filename.
--error 1,1
ALTER SCHEMA schema1 DEFAULT CHARACTER SET utf8;
SET autocommit= TRUE;
--echo # Connection 2
@ -57,7 +58,6 @@ connection con2;
--echo # Connection default
connection default;
DROP SCHEMA schema2;
disconnect con2;
@ -84,7 +84,7 @@ connection con2;
--echo # Connection default
connection default;
let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for table' and info='DROP SCHEMA schema1';
WHERE state='Waiting for schema metadata lock' and info='DROP SCHEMA schema1';
--source include/wait_condition.inc
--echo # CREATE SCHEMA used to give a deadlock.
@ -124,7 +124,7 @@ connection default;
--echo # Connection con2
connect (con2, localhost, root);
let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for table' AND info='DROP DATABASE db1';
WHERE state='Waiting for table metadata lock' AND info='DROP DATABASE db1';
--source include/wait_condition.inc
--echo # Connection con1
@ -172,7 +172,7 @@ connection con2;
--echo # Connection 3
connection con3;
let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for table' and info='DROP DATABASE db1';
WHERE state='Waiting for table metadata lock' and info='DROP DATABASE db1';
--source include/wait_condition.inc
--echo # But it should still be possible to CREATE/ALTER/DROP other databases.
CREATE DATABASE db2;

View File

@ -183,18 +183,19 @@ connection con1;
send drop procedure p1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop procedure t1' to get blocked on MDL lock...
--echo # Waiting for 'drop procedure t1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop procedure p1';
where state='Waiting for stored procedure metadata lock' and
info='drop procedure p1';
--source include/wait_condition.inc
--echo # Demonstrate that there is a pending exclusive lock.
--echo # Sending 'select f1()'...
send select f1();
--echo # --> connection con3
connection con3;
--echo # Waitng for 'select f1()' to get blocked by a pending MDL lock...
--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1()';
where state='Waiting for stored procedure metadata lock' and info='select f1()';
--echo # --> connection default
connection default;
commit;
@ -222,18 +223,19 @@ connection con1;
send create procedure p1() begin end;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'create procedure t1' to get blocked on MDL lock...
--echo # Waiting for 'create procedure t1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='create procedure p1() begin end';
where state='Waiting for stored procedure metadata lock' and
info='create procedure p1() begin end';
--source include/wait_condition.inc
--echo # Demonstrate that there is a pending exclusive lock.
--echo # Sending 'select f1()'...
send select f1();
--echo # --> connection con3
connection con3;
--echo # Waitng for 'select f1()' to get blocked by a pending MDL lock...
--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1()';
where state='Waiting for stored procedure metadata lock' and info='select f1()';
--echo # --> connection default
connection default;
commit;
@ -259,18 +261,19 @@ connection con1;
send alter procedure p1 contains sql;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'alter procedure t1' to get blocked on MDL lock...
--echo # Waiting for 'alter procedure t1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='alter procedure p1 contains sql';
where state='Waiting for stored procedure metadata lock' and
info='alter procedure p1 contains sql';
--source include/wait_condition.inc
--echo # Demonstrate that there is a pending exclusive lock.
--echo # Sending 'select f1()'...
send select f1();
--echo # --> connection con3
connection con3;
--echo # Waitng for 'select f1()' to get blocked by a pending MDL lock...
--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1()';
where state='Waiting for stored procedure metadata lock' and info='select f1()';
--echo # --> connection default
connection default;
commit;
@ -296,18 +299,19 @@ connection con1;
send drop function f1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop function f1' to get blocked on MDL lock...
--echo # Waiting for 'drop function f1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f1';
where state='Waiting for stored function metadata lock' and
info='drop function f1';
--source include/wait_condition.inc
--echo # Demonstrate that there is a pending exclusive lock.
--echo # Sending 'select f1()'...
send select f1();
--echo # --> connection con3
connection con3;
--echo # Waitng for 'select f1()' to get blocked by a pending MDL lock...
--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1()';
where state='Waiting for stored function metadata lock' and info='select f1()';
--echo # --> connection default
connection default;
commit;
@ -335,18 +339,19 @@ connection con1;
send create function f1() returns int return 2;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'create function f1' to get blocked on MDL lock...
--echo # Waiting for 'create function f1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='create function f1() returns int return 2';
where state='Waiting for stored function metadata lock' and
info='create function f1() returns int return 2';
--source include/wait_condition.inc
--echo # Demonstrate that there is a pending exclusive lock.
--echo # Sending 'select f1()'...
send select f1();
--echo # --> connection con3
connection con3;
--echo # Waitng for 'select f1()' to get blocked by a pending MDL lock...
--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1()';
where state='Waiting for stored function metadata lock' and info='select f1()';
--echo # --> connection default
connection default;
commit;
@ -373,18 +378,19 @@ connection con1;
send alter function f1 contains sql;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'alter function f1' to get blocked on MDL lock...
--echo # Waiting for 'alter function f1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='alter function f1 contains sql';
where state='Waiting for stored function metadata lock' and
info='alter function f1 contains sql';
--source include/wait_condition.inc
--echo # Demonstrate that there is a pending exclusive lock.
--echo # Sending 'select f1()'...
send select f1();
--echo # --> connection con3
connection con3;
--echo # Waitng for 'select f1()' to get blocked by a pending MDL lock...
--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1()';
where state='Waiting for stored function metadata lock' and info='select f1()';
--echo # --> connection default
connection default;
commit;
@ -471,9 +477,10 @@ connection con1;
send drop function f1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop function f1' to get blocked on MDL lock...
--echo # Waiting for 'drop function f1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f1';
where state='Waiting for stored function metadata lock' and
info='drop function f1';
--source include/wait_condition.inc
--echo # --> connnection default
connection default;
@ -497,9 +504,10 @@ connection con1;
send drop function f1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop function f1' to get blocked on MDL lock...
--echo # Waiting for 'drop function f1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f1';
where state='Waiting for stored function metadata lock' and
info='drop function f1';
--source include/wait_condition.inc
--echo # --> connnection default
connection default;
@ -530,9 +538,10 @@ connection con1;
send drop procedure p1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop procedure p1' to get blocked on MDL lock...
--echo # Waiting for 'drop procedure p1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop procedure p1';
where state='Waiting for stored procedure metadata lock' and
info='drop procedure p1';
--source include/wait_condition.inc
--echo # --> connnection default
connection default;
@ -561,9 +570,10 @@ connection con1;
send drop function f2;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop function f2' to get blocked on MDL lock...
--echo # Waiting for 'drop function f2' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f2';
where state='Waiting for stored function metadata lock' and
info='drop function f2';
--source include/wait_condition.inc
--echo # --> connnection default
connection default;
@ -623,17 +633,19 @@ connection con1;
send drop function f1;
--echo # --> connection con2
connection con2;
--echo # Waitng for 'drop function f1' to get blocked on MDL lock...
--echo # Waiting for 'drop function f1' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f1';
where state='Waiting for stored function metadata lock' and
info='drop function f1';
--source include/wait_condition.inc
--echo # Sending 'drop function f2'...
send drop function f2;
--echo # --> connection default
connection default;
--echo # Waitng for 'drop function f2' to get blocked on MDL lock...
--echo # Waiting for 'drop function f2' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='drop function f2';
where state='Waiting for stored function metadata lock' and
info='drop function f2';
--source include/wait_condition.inc
rollback to savepoint sv;
--echo # --> connection con2
@ -699,16 +711,18 @@ connection con1;
send alter function f1 comment "comment";
--echo # --> connection con2
connection con2;
--echo # Waitng for 'alter function f1 ...' to get blocked on MDL lock...
--echo # Waiting for 'alter function f1 ...' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info like 'alter function f1 comment%';
where state='Waiting for stored function metadata lock' and
info like 'alter function f1 comment%';
--source include/wait_condition.inc
--echo # Sending 'call p1()'...
send call p1();
connection default;
--echo # Waitng for 'call p1()' to get blocked on MDL lock on f1...
--echo # Waiting for 'call p1()' to get blocked on MDL lock on f1...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1() into @var';
where state='Waiting for stored function metadata lock' and
info='select f1() into @var';
--source include/wait_condition.inc
--echo # Let 'alter function f1 ...' go through...
commit;
@ -746,9 +760,10 @@ connection con1;
send alter function f1 comment "comment";
--echo # --> connection con2
connection con2;
--echo # Waitng for 'alter function f1 ...' to get blocked on MDL lock...
--echo # Waiting for 'alter function f1 ...' to get blocked on MDL lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info like 'alter function f1 comment%';
where state='Waiting for stored function metadata lock' and
info like 'alter function f1 comment%';
--source include/wait_condition.inc
delimiter |;
--echo #
@ -774,9 +789,10 @@ delimiter ;|
--echo # Sending 'call p1()'...
send call p1();
connection default;
--echo # Waitng for 'call p1()' to get blocked on MDL lock on f1...
--echo # Waiting for 'call p1()' to get blocked on MDL lock on f1...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='Waiting for table' and info='select f1() into @var';
where state='Waiting for stored function metadata lock' and
info='select f1() into @var';
--source include/wait_condition.inc
--echo # Let 'alter function f1 ...' go through...
commit;
@ -825,7 +841,7 @@ connection default;
send select f3();
--echo # --> connection con1
connection con1;
--echo # Waitng for 'select f3()' to get blocked on the user level lock...
--echo # Waiting for 'select f3()' to get blocked on the user level lock...
let $wait_condition=select count(*)=1 from information_schema.processlist
where state='User lock' and info='select f1() into @var';
--source include/wait_condition.inc

View File

@ -322,7 +322,7 @@ set session low_priority_updates=on;
connection rl_wait;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and
where state = "Waiting for table level lock" and
info = "update t1 set value='updated' where value='old'";
--source include/wait_condition.inc

View File

@ -87,7 +87,7 @@ SET DEBUG_SYNC= 'now WAIT_FOR locked';
--echo # Connection con3
connection con3;
let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
WHERE state= 'Waiting for table'
WHERE state= 'Waiting for stored function metadata lock'
AND info='SHOW OPEN TABLES WHERE f1()=0';
--source include/wait_condition.inc
--echo # Check that the IS query is blocked before releasing the x-lock

View File

@ -58,7 +58,8 @@ let $ID= `select connection_id()`;
connection con2;
--echo # Switched to connection: con2
# wait for the other query to start executing
let $wait_condition= select 1 from INFORMATION_SCHEMA.PROCESSLIST where ID = $ID and STATE = "Table lock";
let $wait_condition= select 1 from INFORMATION_SCHEMA.PROCESSLIST
where ID = $ID and STATE = "Waiting for table level lock";
--source include/wait_condition.inc
unlock tables;

View File

@ -896,7 +896,7 @@ connection default;
--echo connection: default
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table";
where state = "Waiting for global metadata lock";
--source include/wait_condition.inc
create trigger t1_bi before insert on t1 for each row begin end;
unlock tables;

View File

@ -4074,7 +4074,8 @@ connection default;
connection con2;
let $wait_condition=
SELECT COUNT(*) = 1 from information_schema.processlist
WHERE state = "Table lock" AND info = "INSERT INTO t1 SELECT * FROM v1";
WHERE state = "Waiting for table level lock" AND
info = "INSERT INTO t1 SELECT * FROM v1";
--source include/wait_condition.inc
--echo # ... then try to drop the view. This should block.
--echo # Sending:
@ -4084,7 +4085,7 @@ let $wait_condition=
connection con3;
let $wait_condition=
SELECT COUNT(*) = 1 from information_schema.processlist
WHERE state = "Waiting for table" AND info = "DROP VIEW v1";
WHERE state = "Waiting for table metadata lock" AND info = "DROP VIEW v1";
--source include/wait_condition.inc
--echo # Now allow CALL p1() to complete
UNLOCK TABLES;

View File

@ -428,7 +428,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
thread_var->current_cond= cond;
data->cond= cond;
old_proc_info= proc_info_hook(NULL, "Table lock",
old_proc_info= proc_info_hook(NULL, "Waiting for table level lock",
__func__, __FILE__, __LINE__);
set_timespec(wait_timeout, lock_wait_timeout);

View File

@ -71,6 +71,9 @@ int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
rwp->state = 0;
rwp->waiters = 0;
#ifdef SAFE_MUTEX
rwp->write_thread = 0;
#endif
/* If attribute argument is NULL use default value - prefer writers. */
rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE;
@ -80,6 +83,7 @@ int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
int my_rw_destroy(my_rw_lock_t *rwp)
{
DBUG_ASSERT(rwp->state == 0);
pthread_mutex_destroy( &rwp->lock );
pthread_cond_destroy( &rwp->readers );
pthread_cond_destroy( &rwp->writers );
@ -123,10 +127,15 @@ int my_rw_wrlock(my_rw_lock_t *rwp)
pthread_mutex_lock(&rwp->lock);
rwp->waiters++; /* another writer queued */
my_rw_lock_assert_not_write_owner(rwp);
while (rwp->state)
pthread_cond_wait(&rwp->writers, &rwp->lock);
rwp->state = -1;
rwp->waiters--;
#ifdef SAFE_MUTEX
rwp->write_thread= pthread_self();
#endif
pthread_mutex_unlock(&rwp->lock);
return(0);
}
@ -142,6 +151,9 @@ int my_rw_trywrlock(my_rw_lock_t *rwp)
{
res=0;
rwp->state = -1;
#ifdef SAFE_MUTEX
rwp->write_thread= pthread_self();
#endif
}
pthread_mutex_unlock(&rwp->lock);
return(res);
@ -154,9 +166,15 @@ int my_rw_unlock(my_rw_lock_t *rwp)
("state: %d waiters: %d", rwp->state, rwp->waiters));
pthread_mutex_lock(&rwp->lock);
DBUG_ASSERT(rwp->state != 0);
if (rwp->state == -1) /* writer releasing */
{
my_rw_lock_assert_write_owner(rwp);
rwp->state= 0; /* mark as available */
#ifdef SAFE_MUTEX
rwp->write_thread= 0;
#endif
if ( rwp->waiters ) /* writers queued */
pthread_cond_signal( &rwp->writers );

View File

@ -74,6 +74,7 @@ SET (SQL_SOURCE
sql_profile.cc event_parse_data.cc sql_alter.cc
sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc
transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
sql_reload.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE})

View File

@ -40,6 +40,7 @@ DTRACEFILES = filesort.o \
sql_cursor.o \
sql_delete.o \
sql_truncate.o \
sql_reload.o \
sql_insert.o \
datadict.o \
sql_parse.o \
@ -59,6 +60,7 @@ DTRACEFILES_DEPEND = filesort.o \
sql_cursor.o \
sql_delete.o \
sql_truncate.o \
sql_reload.o \
sql_insert.o \
datadict.o \
sql_parse.o \
@ -126,7 +128,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
contributors.h sql_servers.h sql_signal.h records.h \
sql_prepare.h rpl_handler.h replication.h mdl.h \
sql_plist.h transaction.h sys_vars.h sql_truncate.h \
sql_admin.h datadict.h
sql_admin.h sql_reload.h datadict.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
@ -140,7 +142,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
sql_connect.cc scheduler.cc sql_parse.cc \
keycaches.cc set_var.cc sql_yacc.yy sys_vars.cc \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
datadict.cc sql_profile.cc \
sql_reload.cc datadict.cc sql_profile.cc \
sql_prepare.cc sql_error.cc sql_locale.cc \
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
procedure.cc sql_test.cc sql_admin.cc \

View File

@ -177,9 +177,7 @@ bool dd_recreate_table(THD *thd, const char *db, const char *table_name)
build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
/* Attempt to reconstruct the table. */
mysql_mutex_lock(&LOCK_open);
error= ha_create_table(thd, path, db, table_name, &create_info, TRUE);
mysql_mutex_unlock(&LOCK_open);
DBUG_RETURN(error);
}

View File

@ -996,24 +996,33 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
LEX_STRING name, Event_basic *etn)
{
bool ret;
TABLE *table= NULL;
ulong saved_mode= thd->variables.sql_mode;
Open_tables_backup open_tables_backup;
TABLE_LIST event_table;
DBUG_ENTER("Event_db_repository::load_named_event");
DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd,
(int) name.length, name.str));
event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
/* Reset sql_mode during data dictionary operations. */
thd->variables.sql_mode= 0;
if (!(ret= open_event_table(thd, TL_READ, &table)))
/*
We don't use open_event_table() here to make sure that SHOW
CREATE EVENT works properly in transactional context, and
does not release transactional metadata locks when the
event table is closed.
*/
if (!(ret= open_system_tables_for_read(thd, &event_table, &open_tables_backup)))
{
if ((ret= find_named_event(dbname, name, table)))
if ((ret= find_named_event(dbname, name, event_table.table)))
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
else if ((ret= etn->load_from_row(thd, table)))
else if ((ret= etn->load_from_row(thd, event_table.table)))
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
close_mysql_tables(thd);
close_system_tables(thd, &open_tables_backup);
}
thd->variables.sql_mode= saved_mode;

View File

@ -699,7 +699,6 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
bool
Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
{
Open_tables_backup open_tables_backup;
Event_timed et;
bool ret;
@ -722,9 +721,7 @@ Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
deadlock can occur please refer to the description of 'system table'
flag.
*/
thd->reset_n_backup_open_tables_state(&open_tables_backup);
ret= db_repository->load_named_event(thd, dbname, name, &et);
thd->restore_backup_open_tables_state(&open_tables_backup);
if (!ret)
ret= send_show_create_event(thd, &et, thd->protocol);

View File

@ -680,7 +680,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans)
bzero((char*) &table_list,sizeof(table_list));
table_list.db= m_dbname;
table_list.alias= table_list.table_name= m_tabname;
close_cached_tables(thd, &table_list, FALSE, FALSE);
close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
break;
}
default:
@ -5702,7 +5702,7 @@ int ha_ndbcluster::create(const char *name,
m_table->getObjectVersion(),
(is_truncate) ?
SOT_TRUNCATE_TABLE : SOT_CREATE_TABLE,
0, 0, 1);
0, 0);
break;
}
}
@ -6143,7 +6143,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
old_dbname, m_tabname,
ndb_table_id, ndb_table_version,
SOT_RENAME_TABLE,
m_dbname, new_tabname, 1);
m_dbname, new_tabname);
}
// If we are moving tables between databases, we need to recreate
@ -6337,7 +6337,7 @@ retry_temporary_error1:
thd->query(), thd->query_length(),
share->db, share->table_name,
ndb_table_id, ndb_table_version,
SOT_DROP_TABLE, 0, 0, 1);
SOT_DROP_TABLE, 0, 0);
}
else if (table_dropped && share && share->op) /* ndbcluster_log_schema_op
will do a force GCP */
@ -7019,7 +7019,6 @@ int ndbcluster_drop_database_impl(const char *path)
while ((tabname=it++))
{
tablename_to_filename(tabname, tmp, FN_REFLEN - (tmp - full_path)-1);
mysql_mutex_lock(&LOCK_open);
if (ha_ndbcluster::delete_table(0, ndb, full_path, dbname, tabname))
{
const NdbError err= dict->getNdbError();
@ -7029,7 +7028,6 @@ int ndbcluster_drop_database_impl(const char *path)
ret= ndb_to_mysql_error(&err);
}
}
mysql_mutex_unlock(&LOCK_open);
}
DBUG_RETURN(ret);
}
@ -7056,7 +7054,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path)
ha_ndbcluster::set_dbname(path, db);
ndbcluster_log_schema_op(thd, 0,
thd->query(), thd->query_length(),
db, "", 0, 0, SOT_DROP_DB, 0, 0, 0);
db, "", 0, 0, SOT_DROP_DB, 0, 0);
#endif
DBUG_VOID_RETURN;
}
@ -7181,7 +7179,6 @@ int ndbcluster_find_all_files(THD *thd)
my_free(data);
my_free(pack_data);
mysql_mutex_lock(&LOCK_open);
if (discover)
{
/* ToDo 4.1 database needs to be created if missing */
@ -7199,7 +7196,6 @@ int ndbcluster_find_all_files(THD *thd)
TRUE);
}
#endif
mysql_mutex_unlock(&LOCK_open);
}
}
while (unhandled && retries);
@ -7292,19 +7288,16 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
file_name->str, reg_ext, 0);
if (my_access(name, F_OK))
{
mysql_mutex_lock(&LOCK_open);
DBUG_PRINT("info", ("Table %s listed and need discovery",
file_name->str));
if (ndb_create_table_from_engine(thd, db, file_name->str))
{
mysql_mutex_unlock(&LOCK_open);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TABLE_EXISTS_ERROR,
"Discover of table %s.%s failed",
db, file_name->str);
continue;
}
mysql_mutex_unlock(&LOCK_open);
}
DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name->str));
file_on_disk= TRUE;
@ -7361,10 +7354,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
file_name_str= (char*)my_hash_element(&ok_tables, i);
end= end1 +
tablename_to_filename(file_name_str, end1, sizeof(name) - (end1 - name));
mysql_mutex_lock(&LOCK_open);
ndbcluster_create_binlog_setup(ndb, name, end-name,
db, file_name_str, TRUE);
mysql_mutex_unlock(&LOCK_open);
}
}
#endif
@ -7426,7 +7417,6 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
}
/* Lock mutex before creating .FRM files. */
mysql_mutex_lock(&LOCK_open);
/* Create new files. */
List_iterator_fast<char> it2(create_list);
while ((file_name_str=it2++))
@ -7441,8 +7431,6 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
}
}
mysql_mutex_unlock(&LOCK_open);
my_hash_free(&ok_tables);
my_hash_free(&ndb_tables);
@ -8452,8 +8440,7 @@ int handle_trailing_share(NDB_SHARE *share)
bzero((char*) &table_list,sizeof(table_list));
table_list.db= share->db;
table_list.alias= table_list.table_name= share->table_name;
mysql_mutex_assert_owner(&LOCK_open);
close_cached_tables(thd, &table_list, TRUE, FALSE);
close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
mysql_mutex_lock(&ndbcluster_mutex);
/* ndb_share reference temporary free */
@ -10612,13 +10599,13 @@ int ndbcluster_alter_tablespace(handlerton *hton,
thd->query(), thd->query_length(),
"", alter_info->tablespace_name,
0, 0,
SOT_TABLESPACE, 0, 0, 0);
SOT_TABLESPACE, 0, 0);
else
ndbcluster_log_schema_op(thd, 0,
thd->query(), thd->query_length(),
"", alter_info->logfile_group_name,
0, 0,
SOT_LOGFILE_GROUP, 0, 0, 0);
SOT_LOGFILE_GROUP, 0, 0);
#endif
DBUG_RETURN(FALSE);

View File

@ -360,7 +360,6 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
int error;
DBUG_ENTER("ndbcluster_binlog_open_table");
mysql_mutex_assert_owner(&LOCK_open);
init_tmp_table_share(thd, table_share, share->db, 0, share->table_name,
share->key);
if ((error= open_table_def(thd, table_share, 0)))
@ -376,7 +375,9 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
free_table_share(table_share);
DBUG_RETURN(error);
}
mysql_mutex_lock(&LOCK_open);
assign_new_table_id(table_share);
mysql_mutex_unlock(&LOCK_open);
if (!reopen)
{
@ -625,7 +626,7 @@ ndbcluster_binlog_log_query(handlerton *hton, THD *thd, enum_binlog_command binl
{
ndbcluster_log_schema_op(thd, 0, query, query_length,
db, table_name, 0, 0, type,
0, 0, 0);
0, 0);
}
DBUG_VOID_RETURN;
}
@ -908,9 +909,7 @@ int ndbcluster_setup_binlog_table_shares(THD *thd)
if (!ndb_schema_share &&
ndbcluster_check_ndb_schema_share() == 0)
{
mysql_mutex_lock(&LOCK_open);
ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_SCHEMA_TABLE);
mysql_mutex_unlock(&LOCK_open);
if (!ndb_schema_share)
{
ndbcluster_create_schema_table(thd);
@ -922,9 +921,7 @@ int ndbcluster_setup_binlog_table_shares(THD *thd)
if (!ndb_apply_status_share &&
ndbcluster_check_ndb_apply_status_share() == 0)
{
mysql_mutex_lock(&LOCK_open);
ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_APPLY_TABLE);
mysql_mutex_unlock(&LOCK_open);
if (!ndb_apply_status_share)
{
ndbcluster_create_ndb_apply_status_table(thd);
@ -934,12 +931,10 @@ int ndbcluster_setup_binlog_table_shares(THD *thd)
}
if (!ndbcluster_find_all_files(thd))
{
mysql_mutex_lock(&LOCK_open);
ndb_binlog_tables_inited= TRUE;
if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: ndb tables writable");
close_cached_tables(NULL, NULL, TRUE, FALSE);
mysql_mutex_unlock(&LOCK_open);
close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT);
/* Signal injector thread that all is setup */
mysql_cond_signal(&injector_cond);
}
@ -1276,8 +1271,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
uint32 ndb_table_id,
uint32 ndb_table_version,
enum SCHEMA_OP_TYPE type,
const char *new_db, const char *new_table_name,
int have_lock_open)
const char *new_db, const char *new_table_name)
{
DBUG_ENTER("ndbcluster_log_schema_op");
Thd_ndb *thd_ndb= get_thd_ndb(thd);
@ -1580,11 +1574,6 @@ end:
int max_timeout= DEFAULT_SYNC_TIMEOUT;
mysql_mutex_lock(&ndb_schema_object->mutex);
if (have_lock_open)
{
mysql_mutex_assert_owner(&LOCK_open);
mysql_mutex_unlock(&LOCK_open);
}
while (1)
{
struct timespec abstime;
@ -1640,10 +1629,6 @@ end:
"distributing", ndb_schema_object->key);
}
}
if (have_lock_open)
{
mysql_mutex_lock(&LOCK_open);
}
mysql_mutex_unlock(&ndb_schema_object->mutex);
}
@ -1726,7 +1711,6 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
{
DBUG_DUMP("frm", (uchar*) altered_table->getFrmData(),
altered_table->getFrmLength());
mysql_mutex_lock(&LOCK_open);
Ndb_table_guard ndbtab_g(dict, tabname);
const NDBTAB *old= ndbtab_g.get_table();
if (!old &&
@ -1752,7 +1736,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= (char *)dbname;
table_list.alias= table_list.table_name= (char *)tabname;
close_cached_tables(thd, &table_list, TRUE, FALSE);
close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
if ((error= ndbcluster_binlog_open_table(thd, share,
table_share, table, 1)))
@ -1763,8 +1747,6 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
table_share= share->table_share;
dbname= table_share->db.str;
tabname= table_share->table_name.str;
mysql_mutex_unlock(&LOCK_open);
}
my_free(data);
my_free(pack_data);
@ -1858,7 +1840,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= (char *)dbname;
table_list.alias= table_list.table_name= (char *)tabname;
close_cached_tables(thd, &table_list, FALSE, FALSE);
close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
/* ndb_share reference create free */
DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
share->key, share->use_count));
@ -1979,7 +1961,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= schema->db;
table_list.alias= table_list.table_name= schema->name;
close_cached_tables(thd, &table_list, FALSE, FALSE);
close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
}
/* ndb_share reference temporary free */
if (share)
@ -1991,7 +1973,6 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
}
// fall through
case SOT_CREATE_TABLE:
mysql_mutex_lock(&LOCK_open);
if (ndbcluster_check_if_local_table(schema->db, schema->name))
{
DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
@ -2005,7 +1986,6 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
{
print_could_not_discover_error(thd, schema);
}
mysql_mutex_unlock(&LOCK_open);
log_query= 1;
break;
case SOT_DROP_DB:
@ -2096,7 +2076,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
mysql_mutex_unlock(&ndb_schema_share_mutex);
/* end protect ndb_schema_share */
close_cached_tables(NULL, NULL, FALSE, FALSE);
close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT);
// fall through
case NDBEVENT::TE_ALTER:
ndb_handle_schema_change(thd, ndb, pOp, tmp_share);
@ -2253,7 +2233,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= schema->db;
table_list.alias= table_list.table_name= schema->name;
close_cached_tables(thd, &table_list, FALSE, FALSE);
close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
}
if (schema_type != SOT_ALTER_TABLE)
break;
@ -2274,7 +2254,6 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
free_share(&share);
share= 0;
}
mysql_mutex_lock(&LOCK_open);
if (ndbcluster_check_if_local_table(schema->db, schema->name))
{
DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
@ -2288,7 +2267,6 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
{
print_could_not_discover_error(thd, schema);
}
mysql_mutex_unlock(&LOCK_open);
}
break;
default:
@ -3154,8 +3132,6 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
#ifdef SYNC_DROP_
thd->proc_info= "Syncing ndb table schema operation and binlog";
mysql_mutex_lock(&share->mutex);
mysql_mutex_assert_owner(&LOCK_open);
mysql_mutex_unlock(&LOCK_open);
int max_timeout= DEFAULT_SYNC_TIMEOUT;
while (share->op)
{
@ -3181,7 +3157,6 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
type_str, share->key);
}
}
mysql_mutex_lock(&LOCK_open);
mysql_mutex_unlock(&share->mutex);
#else
mysql_mutex_lock(&share->mutex);
@ -3963,9 +3938,9 @@ restart:
!ndb_binlog_running))
break; /* Shutting down server */
if (ndb_binlog_index && ndb_binlog_index->s->needs_reopen())
if (ndb_binlog_index && ndb_binlog_index->s->has_old_version())
{
if (ndb_binlog_index->s->needs_reopen())
if (ndb_binlog_index->s->has_old_version())
{
trans_commit_stmt(thd);
close_thread_tables(thd);

View File

@ -158,8 +158,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
uint32 ndb_table_version,
enum SCHEMA_OP_TYPE type,
const char *new_db,
const char *new_table_name,
int have_lock_open);
const char *new_table_name);
int ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
NDB_SHARE *share,
const char *type_str);

View File

@ -3670,6 +3670,34 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
DBUG_RETURN(error != 0);
}
/**
Try to find a table in a storage engine.
@param db Normalized table schema name
@param name Normalized table name.
@param[out] exists Only valid if the function succeeded.
@retval TRUE An error is found
@retval FALSE Success, check *exists
*/
bool
ha_check_if_table_exists(THD* thd, const char *db, const char *name,
bool *exists)
{
uchar *frmblob= NULL;
size_t frmlen;
DBUG_ENTER("ha_check_if_table_exists");
*exists= ! ha_discover(thd, db, name, &frmblob, &frmlen);
if (*exists)
my_free(frmblob);
DBUG_RETURN(FALSE);
}
void st_ha_check_opt::init()
{
flags= sql_flags= 0;

View File

@ -2119,6 +2119,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
/* discovery */
int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
bool ha_check_if_table_exists(THD* thd, const char *db, const char *name,
bool *exists);
int ha_discover(THD* thd, const char* dbname, const char* name,
uchar** frmblob, size_t* frmlen);
int ha_find_files(THD *thd,const char *db,const char *path,

View File

@ -1298,27 +1298,19 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
/**
Broadcast COND_refresh and COND_global_read_lock.
Broadcast COND_global_read_lock.
Due to a bug in a threading library it could happen that a signal
did not reach its target. A condition for this was that the same
condition variable was used with different mutexes in
mysql_cond_wait(). Some time ago we changed LOCK_open to
LOCK_global_read_lock in global read lock handling. So COND_refresh
was used with LOCK_open and LOCK_global_read_lock.
We did now also change from COND_refresh to COND_global_read_lock
in global read lock handling. But now it is necessary to signal
both conditions at the same time.
@note
When signalling COND_global_read_lock within the global read lock
handling, it is not necessary to also signal COND_refresh.
TODO/FIXME: Dmitry thinks that we broadcast on COND_global_read_lock
when old instance of table is closed to avoid races
between incrementing refresh_version and
wait_if_global_read_lock(thd, TRUE, FALSE) call.
Once global read lock implementation starts using MDL
infrastructure this will became unnecessary and should
be removed.
*/
void broadcast_refresh(void)
{
mysql_cond_broadcast(&COND_refresh);
mysql_cond_broadcast(&COND_global_read_lock);
}

View File

@ -9,48 +9,6 @@ struct TABLE_LIST;
class THD;
typedef struct st_mysql_lock MYSQL_LOCK;
/* mysql_lock_tables() and open_table() flags bits */
#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
#define MYSQL_LOCK_LOG_TABLE 0x0010
/**
Do not try to acquire a metadata lock on the table: we
already have one.
*/
#define MYSQL_OPEN_HAS_MDL_LOCK 0x0020
/**
If in locked tables mode, ignore the locked tables and get
a new instance of the table.
*/
#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
/** Don't look up the table in the list of temporary tables. */
#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
/** Fail instead of waiting when conficting metadata lock is discovered. */
#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200
/**
Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified
in parser.
*/
#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400
/**
When opening or locking the table, use the maximum timeout
(LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
*/
#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
/** Please refer to the internals manual. */
#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |\
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
MYSQL_LOCK_IGNORE_TIMEOUT |\
MYSQL_OPEN_GET_NEW_TABLE |\
MYSQL_OPEN_SKIP_TEMPORARY |\
MYSQL_OPEN_HAS_MDL_LOCK)
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);

View File

@ -71,6 +71,21 @@ static void init_mdl_psi_keys(void)
void notify_shared_lock(THD *thd, MDL_ticket *conflicting_ticket);
/**
Thread state names to be used in case when we have to wait on resource
belonging to certain namespace.
*/
const char *MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
{
"Waiting for global metadata lock",
"Waiting for schema metadata lock",
"Waiting for table metadata lock",
"Waiting for stored function metadata lock",
"Waiting for stored procedure metadata lock",
NULL
};
static bool mdl_initialized= 0;
@ -98,38 +113,32 @@ private:
};
enum enum_deadlock_weight
{
MDL_DEADLOCK_WEIGHT_DML= 0,
MDL_DEADLOCK_WEIGHT_DDL= 100
};
/**
A context of the recursive traversal through all contexts
in all sessions in search for deadlock.
*/
class Deadlock_detection_visitor
class Deadlock_detection_visitor: public MDL_wait_for_graph_visitor
{
public:
Deadlock_detection_visitor(MDL_context *start_node_arg)
: m_start_node(start_node_arg),
m_victim(NULL),
m_current_search_depth(0)
m_current_search_depth(0),
m_found_deadlock(FALSE)
{}
bool enter_node(MDL_context * /* unused */);
void leave_node(MDL_context * /* unused */);
virtual bool enter_node(MDL_context *node);
virtual void leave_node(MDL_context *node);
bool inspect_edge(MDL_context *dest);
virtual bool inspect_edge(MDL_context *dest);
MDL_context *get_victim() const { return m_victim; }
private:
/**
Change the deadlock victim to a new one if it has lower deadlock
weight.
*/
MDL_context *opt_change_victim_to(MDL_context *new_victim);
void opt_change_victim_to(MDL_context *new_victim);
private:
/**
The context which has initiated the search. There
@ -145,6 +154,8 @@ private:
loop.
*/
uint m_current_search_depth;
/** TRUE if we found a deadlock. */
bool m_found_deadlock;
/**
Maximum depth for deadlock searches. After this depth is
achieved we will unconditionally declare that there is a
@ -167,29 +178,38 @@ private:
a node is entered, inspect_edge() will be called
for all wait-for destinations of this node. Then
leave_node() will be called.
We call "enter_node()" for all nodes we inspect,
We call "enter_node()" for all nodes we inspect,
including the starting node.
@retval TRUE Maximum search depth exceeded.
@retval FALSE OK.
*/
bool Deadlock_detection_visitor::enter_node(MDL_context * /* unused */)
bool Deadlock_detection_visitor::enter_node(MDL_context *node)
{
if (++m_current_search_depth >= MAX_SEARCH_DEPTH)
return TRUE;
return FALSE;
m_found_deadlock= ++m_current_search_depth >= MAX_SEARCH_DEPTH;
if (m_found_deadlock)
{
DBUG_ASSERT(! m_victim);
opt_change_victim_to(node);
}
return m_found_deadlock;
}
/**
Done inspecting this node. Decrease the search
depth. Clear the node for debug safety.
depth. If a deadlock is found, and we are
backtracking to the start node, optionally
change the deadlock victim to one with lower
deadlock weight.
*/
void Deadlock_detection_visitor::leave_node(MDL_context * /* unused */)
void Deadlock_detection_visitor::leave_node(MDL_context *node)
{
--m_current_search_depth;
if (m_found_deadlock)
opt_change_victim_to(node);
}
@ -202,7 +222,8 @@ void Deadlock_detection_visitor::leave_node(MDL_context * /* unused */)
bool Deadlock_detection_visitor::inspect_edge(MDL_context *node)
{
return node == m_start_node;
m_found_deadlock= node == m_start_node;
return m_found_deadlock;
}
@ -214,7 +235,7 @@ bool Deadlock_detection_visitor::inspect_edge(MDL_context *node)
@retval !new_victim New victim became the current.
*/
MDL_context *
void
Deadlock_detection_visitor::opt_change_victim_to(MDL_context *new_victim)
{
if (m_victim == NULL ||
@ -223,10 +244,10 @@ Deadlock_detection_visitor::opt_change_victim_to(MDL_context *new_victim)
/* Swap victims, unlock the old one. */
MDL_context *tmp= m_victim;
m_victim= new_victim;
return tmp;
m_victim->lock_deadlock_victim();
if (tmp)
tmp->unlock_deadlock_victim();
}
/* No change, unlock the current context. */
return new_victim;
}
@ -349,8 +370,8 @@ public:
void remove_ticket(Ticket_list MDL_lock::*queue, MDL_ticket *ticket);
bool find_deadlock(MDL_ticket *waiting_ticket,
Deadlock_detection_visitor *dvisitor);
bool visit_subgraph(MDL_ticket *waiting_ticket,
MDL_wait_for_graph_visitor *gvisitor);
/** List of granted tickets for this lock. */
Ticket_list m_granted;
@ -479,14 +500,6 @@ mdl_locks_key(const uchar *record, size_t *length,
the associated condition variable: LOCK_mdl and COND_mdl.
These locking primitives are implementation details of the MDL
subsystem and are private to it.
Note, that even though the new implementation adds acquisition
of a new global mutex to the execution flow of almost every SQL
statement, the design capitalizes on that to later save on
look ups in the table definition cache. This leads to reduced
contention overall and on LOCK_open in particular.
Please see the description of MDL_context::acquire_lock()
for details.
*/
void mdl_init()
@ -876,8 +889,8 @@ void MDL_ticket::destroy(MDL_ticket *ticket)
uint MDL_ticket::get_deadlock_weight() const
{
return (m_lock->key.mdl_namespace() == MDL_key::GLOBAL ||
m_type > MDL_SHARED_NO_WRITE ?
MDL_DEADLOCK_WEIGHT_DDL : MDL_DEADLOCK_WEIGHT_DML);
m_type >= MDL_SHARED_NO_WRITE ?
DEADLOCK_WEIGHT_DDL : DEADLOCK_WEIGHT_DML);
}
@ -946,17 +959,18 @@ void MDL_wait::reset_status()
Wait for the status to be assigned to this wait slot.
@param abs_timeout Absolute time after which waiting should stop.
@param set_status_on_tiemout TRUE - If in case of timeout waiting
context should close the wait slot by
sending TIMEOUT to itself.
FALSE - Otherwise.
@param set_status_on_timeout TRUE - If in case of timeout waiting
context should close the wait slot by
sending TIMEOUT to itself.
FALSE - Otherwise.
@param wait_state_name Thread state name to be set for duration of wait.
@returns Signal posted.
*/
MDL_wait::enum_wait_status
MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
bool set_status_on_timeout)
bool set_status_on_timeout, const char *wait_state_name)
{
const char *old_msg;
enum_wait_status result;
@ -965,7 +979,7 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
mysql_mutex_lock(&m_LOCK_wait_status);
old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status,
"Waiting for table");
wait_state_name);
while (!m_wait_status && !thd_killed(thd) &&
wait_result != ETIMEDOUT && wait_result != ETIME)
@ -1380,6 +1394,15 @@ bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type)
}
MDL_wait_for_graph_visitor::~MDL_wait_for_graph_visitor()
{
}
MDL_wait_for_subgraph::~MDL_wait_for_subgraph()
{
}
/**
Check if ticket represents metadata lock of "stronger" or equal type
than specified one. I.e. if metadata lock represented by ticket won't
@ -1528,9 +1551,8 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
MDL_ticket *ticket;
bool is_transactional;
DBUG_ASSERT(mdl_request->type < MDL_SHARED_NO_WRITE ||
(is_lock_owner(MDL_key::GLOBAL, "", "",
MDL_INTENTION_EXCLUSIVE)));
DBUG_ASSERT(mdl_request->type != MDL_EXCLUSIVE ||
is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE));
DBUG_ASSERT(mdl_request->ticket == NULL);
/* Don't take chances in production. */
@ -1746,7 +1768,8 @@ MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
while (cmp_timespec(abs_shortwait, abs_timeout) <= 0)
{
/* abs_timeout is far away. Wait a short while and notify locks. */
wait_status= m_wait.timed_wait(m_thd, &abs_shortwait, FALSE);
wait_status= m_wait.timed_wait(m_thd, &abs_shortwait, FALSE,
mdl_request->key.get_wait_state_name());
if (wait_status != MDL_wait::EMPTY)
break;
@ -1757,10 +1780,12 @@ MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
set_timespec(abs_shortwait, 1);
}
if (wait_status == MDL_wait::EMPTY)
wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE);
wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE,
mdl_request->key.get_wait_state_name());
}
else
wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE);
wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE,
mdl_request->key.get_wait_state_name());
done_waiting_for();
@ -1952,8 +1977,17 @@ MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket,
}
bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
Deadlock_detection_visitor *dvisitor)
/**
A fragment of recursive traversal of the wait-for graph
in search for deadlocks. Direct the deadlock visitor to all
contexts that own the lock the current node in the wait-for
graph is waiting for.
As long as the initial node is remembered in the visitor,
a deadlock is found when the same node is seen twice.
*/
bool MDL_lock::visit_subgraph(MDL_ticket *waiting_ticket,
MDL_wait_for_graph_visitor *gvisitor)
{
MDL_ticket *ticket;
MDL_context *src_ctx= waiting_ticket->get_ctx();
@ -2022,7 +2056,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
are visiting it but this is OK: in the worst case we might do some
extra work and one more context might be chosen as a victim.
*/
if (dvisitor->enter_node(src_ctx))
if (gvisitor->enter_node(src_ctx))
goto end;
/*
@ -2036,7 +2070,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
/* Filter out edges that point to the same node. */
if (ticket->get_ctx() != src_ctx &&
ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
dvisitor->inspect_edge(ticket->get_ctx()))
gvisitor->inspect_edge(ticket->get_ctx()))
{
goto end_leave_node;
}
@ -2047,7 +2081,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
/* Filter out edges that point to the same node. */
if (ticket->get_ctx() != src_ctx &&
ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
dvisitor->inspect_edge(ticket->get_ctx()))
gvisitor->inspect_edge(ticket->get_ctx()))
{
goto end_leave_node;
}
@ -2059,7 +2093,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
{
if (ticket->get_ctx() != src_ctx &&
ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
ticket->get_ctx()->find_deadlock(dvisitor))
ticket->get_ctx()->visit_subgraph(gvisitor))
{
goto end_leave_node;
}
@ -2070,7 +2104,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
{
if (ticket->get_ctx() != src_ctx &&
ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
ticket->get_ctx()->find_deadlock(dvisitor))
ticket->get_ctx()->visit_subgraph(gvisitor))
{
goto end_leave_node;
}
@ -2079,7 +2113,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket,
result= FALSE;
end_leave_node:
dvisitor->leave_node(src_ctx);
gvisitor->leave_node(src_ctx);
end:
mysql_prlock_unlock(&m_rwlock);
@ -2088,35 +2122,47 @@ end:
/**
Recursively traverse the wait-for graph of MDL contexts
in search for deadlocks.
Traverse a portion of wait-for graph which is reachable
through the edge represented by this ticket and search
for deadlocks.
@retval TRUE A deadlock is found. A victim is remembered
by the visitor.
@retval TRUE A deadlock is found. A pointer to deadlock
victim is saved in the visitor.
@retval FALSE
*/
bool MDL_context::find_deadlock(Deadlock_detection_visitor *dvisitor)
bool MDL_ticket::accept_visitor(MDL_wait_for_graph_visitor *gvisitor)
{
return m_lock->visit_subgraph(this, gvisitor);
}
/**
A fragment of recursive traversal of the wait-for graph of
MDL contexts in the server in search for deadlocks.
Assume this MDL context is a node in the wait-for graph,
and direct the visitor to all adjacent nodes. As long
as the starting node is remembered in the visitor, a
deadlock is found when the same node is visited twice.
One MDL context is connected to another in the wait-for
graph if it waits on a resource that is held by the other
context.
@retval TRUE A deadlock is found. A pointer to deadlock
victim is saved in the visitor.
@retval FALSE
*/
bool MDL_context::visit_subgraph(MDL_wait_for_graph_visitor *gvisitor)
{
MDL_context *m_unlock_ctx= this;
bool result= FALSE;
mysql_prlock_rdlock(&m_LOCK_waiting_for);
if (m_waiting_for)
{
result= m_waiting_for->m_lock->find_deadlock(m_waiting_for, dvisitor);
if (result)
m_unlock_ctx= dvisitor->opt_change_victim_to(this);
}
/*
We may recurse into the same MDL_context more than once
in case this is not the starting node. Make sure we release the
read lock as it's been taken, except for 1 read lock for
the deadlock victim.
*/
if (m_unlock_ctx)
mysql_prlock_unlock(&m_unlock_ctx->m_LOCK_waiting_for);
result= m_waiting_for->accept_visitor(gvisitor);
mysql_prlock_unlock(&m_LOCK_waiting_for);
return result;
}
@ -2138,14 +2184,14 @@ void MDL_context::find_deadlock()
while (1)
{
/*
The fact that we use fresh instance of dvisitor for each
The fact that we use fresh instance of gvisitor for each
search performed by find_deadlock() below is important,
the code responsible for victim selection relies on this.
*/
Deadlock_detection_visitor dvisitor(this);
MDL_context *victim;
if (! find_deadlock(&dvisitor))
if (! visit_subgraph(&dvisitor))
{
/* No deadlocks are found! */
break;
@ -2166,7 +2212,7 @@ void MDL_context::find_deadlock()
context was waiting is concurrently satisfied.
*/
(void) victim->m_wait.set_status(MDL_wait::VICTIM);
mysql_prlock_unlock(&victim->m_LOCK_waiting_for);
victim->unlock_deadlock_victim();
if (victim == this)
break;

View File

@ -34,7 +34,6 @@ class THD;
class MDL_context;
class MDL_lock;
class MDL_ticket;
class Deadlock_detection_visitor;
/**
Type of metadata lock request.
@ -184,7 +183,9 @@ public:
TABLE,
FUNCTION,
PROCEDURE,
TRIGGER };
TRIGGER,
/* This should be the last ! */
NAMESPACE_END };
const uchar *ptr() const { return (uchar*) m_ptr; }
uint length() const { return m_length; }
@ -251,10 +252,20 @@ public:
}
MDL_key() {} /* To use when part of MDL_request. */
/**
Get thread state name to be used in case when we have to
wait on resource identified by key.
*/
const char * get_wait_state_name() const
{
return m_namespace_to_wait_state_name[(int)mdl_namespace()];
}
private:
uint16 m_length;
uint16 m_db_name_length;
char m_ptr[MAX_MDLKEY_LENGTH];
static const char * m_namespace_to_wait_state_name[NAMESPACE_END];
private:
MDL_key(const MDL_key &); /* not implemented */
MDL_key &operator=(const MDL_key &); /* not implemented */
@ -360,6 +371,59 @@ public:
typedef void (*mdl_cached_object_release_hook)(void *);
/**
An abstract class for inspection of a connected
subgraph of the wait-for graph.
*/
class MDL_wait_for_graph_visitor
{
public:
virtual bool enter_node(MDL_context *node) = 0;
virtual void leave_node(MDL_context *node) = 0;
virtual bool inspect_edge(MDL_context *dest) = 0;
virtual ~MDL_wait_for_graph_visitor();
MDL_wait_for_graph_visitor() :m_lock_open_count(0) {}
public:
/**
XXX, hack: During deadlock search, we may need to
inspect TABLE_SHAREs and acquire LOCK_open. Since
LOCK_open is not a recursive mutex, count here how many
times we "took" it (but only take and release once).
Not using a native recursive mutex or rwlock in 5.5 for
LOCK_open since it has significant performance impacts.
*/
uint m_lock_open_count;
};
/**
Abstract class representing an edge in the waiters graph
to be traversed by deadlock detection algorithm.
*/
class MDL_wait_for_subgraph
{
public:
virtual ~MDL_wait_for_subgraph();
/**
Accept a wait-for graph visitor to inspect the node
this edge is leading to.
*/
virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0;
enum enum_deadlock_weight
{
DEADLOCK_WEIGHT_DML= 0,
DEADLOCK_WEIGHT_DDL= 100
};
/* A helper used to determine which lock request should be aborted. */
virtual uint get_deadlock_weight() const = 0;
};
/**
A granted metadata lock.
@ -380,7 +444,7 @@ typedef void (*mdl_cached_object_release_hook)(void *);
threads/contexts.
*/
class MDL_ticket
class MDL_ticket : public MDL_wait_for_subgraph
{
public:
/**
@ -414,8 +478,9 @@ public:
bool is_incompatible_when_granted(enum_mdl_type type) const;
bool is_incompatible_when_waiting(enum_mdl_type type) const;
/* A helper used to determine which lock request should be aborted. */
uint get_deadlock_weight() const;
/** Implement MDL_wait_for_subgraph interface. */
virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor);
virtual uint get_deadlock_weight() const;
private:
friend class MDL_context;
@ -462,7 +527,7 @@ public:
enum_wait_status get_status();
void reset_status();
enum_wait_status timed_wait(THD *thd, struct timespec *abs_timeout,
bool signal_timeout);
bool signal_timeout, const char *wait_state_name);
private:
/**
Condvar which is used for waiting until this context's pending
@ -582,8 +647,6 @@ public:
{
return m_needs_thr_lock_abort;
}
bool find_deadlock(Deadlock_detection_visitor *dvisitor);
public:
/**
If our request for a lock is scheduled, or aborted by the deadlock
@ -675,12 +738,13 @@ private:
*/
mysql_prlock_t m_LOCK_waiting_for;
/**
Tell the deadlock detector what lock this session is waiting for.
Tell the deadlock detector what metadata lock or table
definition cache entry this session is waiting for.
In principle, this is redundant, as information can be found
by inspecting waiting queues, but we'd very much like it to be
readily available to the wait-for graph iterator.
*/
MDL_ticket *m_waiting_for;
MDL_wait_for_subgraph *m_waiting_for;
private:
MDL_ticket *find_ticket(MDL_request *mdl_req,
bool *is_transactional);
@ -688,13 +752,16 @@ private:
bool try_acquire_lock_impl(MDL_request *mdl_request,
MDL_ticket **out_ticket);
public:
void find_deadlock();
bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor);
/** Inform the deadlock detector there is an edge in the wait-for graph. */
void will_wait_for(MDL_ticket *pending_ticket)
void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg)
{
mysql_prlock_wrlock(&m_LOCK_waiting_for);
m_waiting_for= pending_ticket;
m_waiting_for= waiting_for_arg;
mysql_prlock_unlock(&m_LOCK_waiting_for);
}
@ -705,6 +772,14 @@ private:
m_waiting_for= NULL;
mysql_prlock_unlock(&m_LOCK_waiting_for);
}
void lock_deadlock_victim()
{
mysql_prlock_rdlock(&m_LOCK_waiting_for);
}
void unlock_deadlock_victim()
{
mysql_prlock_unlock(&m_LOCK_waiting_for);
}
private:
MDL_context(const MDL_context &rhs); /* not implemented */
MDL_context &operator=(MDL_context &rhs); /* not implemented */

View File

@ -87,6 +87,7 @@
#include <errmsg.h>
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_reload.h" // reload_acl_and_cache
#ifdef HAVE_POLL_H
#include <poll.h>
@ -601,7 +602,7 @@ SHOW_COMP_OPTION have_profiling;
pthread_key(MEM_ROOT**,THR_MALLOC);
pthread_key(THD*, THR_THD);
mysql_mutex_t LOCK_thread_count;
mysql_mutex_t LOCK_open,
mysql_mutex_t
LOCK_status, LOCK_global_read_lock,
LOCK_error_log, LOCK_uuid_generator,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
@ -623,7 +624,7 @@ mysql_mutex_t LOCK_des_key_file;
mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
mysql_rwlock_t LOCK_system_variables_hash;
mysql_cond_t COND_thread_count;
mysql_cond_t COND_refresh, COND_global_read_lock;
mysql_cond_t COND_global_read_lock;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
mysql_mutex_t LOCK_server_started;
@ -1526,7 +1527,6 @@ static void wait_for_signal_thread_to_end()
static void clean_up_mutexes()
{
mysql_rwlock_destroy(&LOCK_grant);
mysql_mutex_destroy(&LOCK_open);
mysql_mutex_destroy(&LOCK_thread_count);
mysql_mutex_destroy(&LOCK_status);
mysql_mutex_destroy(&LOCK_delayed_insert);
@ -1559,7 +1559,6 @@ static void clean_up_mutexes()
mysql_mutex_destroy(&LOCK_prepared_stmt_count);
mysql_mutex_destroy(&LOCK_error_messages);
mysql_cond_destroy(&COND_thread_count);
mysql_cond_destroy(&COND_refresh);
mysql_cond_destroy(&COND_global_read_lock);
mysql_cond_destroy(&COND_thread_cache);
mysql_cond_destroy(&COND_flush_thread_cache);
@ -3500,7 +3499,6 @@ You should consider changing lower_case_table_names to 1 or 2",
static int init_thread_environment()
{
mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_thread_count, &LOCK_thread_count, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_status, &LOCK_status, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_delayed_insert,
@ -3547,7 +3545,6 @@ static int init_thread_environment()
mysql_rwlock_init(key_rwlock_LOCK_sys_init_slave, &LOCK_sys_init_slave);
mysql_rwlock_init(key_rwlock_LOCK_grant, &LOCK_grant);
mysql_cond_init(key_COND_thread_count, &COND_thread_count, NULL);
mysql_cond_init(key_COND_refresh, &COND_refresh, NULL);
mysql_cond_init(key_COND_global_read_lock, &COND_global_read_lock, NULL);
mysql_cond_init(key_COND_thread_cache, &COND_thread_cache, NULL);
mysql_cond_init(key_COND_flush_thread_cache, &COND_flush_thread_cache, NULL);
@ -7682,7 +7679,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables,
key_LOCK_manager,
key_LOCK_open, key_LOCK_prepared_stmt_count,
key_LOCK_prepared_stmt_count,
key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
key_LOCK_system_variables_hash, key_LOCK_table_share, key_LOCK_thd_data,
key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log,
@ -7721,7 +7718,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_global_read_lock, "LOCK_global_read_lock", PSI_FLAG_GLOBAL},
{ &key_LOCK_global_system_variables, "LOCK_global_system_variables", PSI_FLAG_GLOBAL},
{ &key_LOCK_manager, "LOCK_manager", PSI_FLAG_GLOBAL},
{ &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL},
{ &key_LOCK_prepared_stmt_count, "LOCK_prepared_stmt_count", PSI_FLAG_GLOBAL},
{ &key_LOCK_rpl_status, "LOCK_rpl_status", PSI_FLAG_GLOBAL},
{ &key_LOCK_server_started, "LOCK_server_started", PSI_FLAG_GLOBAL},
@ -7769,7 +7765,7 @@ PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
key_COND_cache_status_changed, key_COND_global_read_lock, key_COND_manager,
key_COND_refresh, key_COND_rpl_status, key_COND_server_started,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
key_item_func_sleep_cond, key_master_info_data_cond,
key_master_info_start_cond, key_master_info_stop_cond,
@ -7793,7 +7789,6 @@ static PSI_cond_info all_server_conds[]=
{ &key_COND_cache_status_changed, "Query_cache::COND_cache_status_changed", 0},
{ &key_COND_global_read_lock, "COND_global_read_lock", PSI_FLAG_GLOBAL},
{ &key_COND_manager, "COND_manager", PSI_FLAG_GLOBAL},
{ &key_COND_refresh, "COND_refresh", PSI_FLAG_GLOBAL},
{ &key_COND_rpl_status, "COND_rpl_status", PSI_FLAG_GLOBAL},
{ &key_COND_server_started, "COND_server_started", PSI_FLAG_GLOBAL},
{ &key_delayed_insert_cond, "Delayed_insert::cond", 0},

View File

@ -229,7 +229,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables,
key_LOCK_logger, key_LOCK_manager,
key_LOCK_open, key_LOCK_prepared_stmt_count,
key_LOCK_prepared_stmt_count,
key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
key_LOCK_table_share, key_LOCK_thd_data,
key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log,
@ -249,7 +249,7 @@ extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
extern PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
key_COND_cache_status_changed, key_COND_global_read_lock, key_COND_manager,
key_COND_refresh, key_COND_rpl_status, key_COND_server_started,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
key_item_func_sleep_cond, key_master_info_data_cond,
key_master_info_start_cond, key_master_info_stop_cond,
@ -316,7 +316,7 @@ extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded
/*
Server mutex locks and condition variables.
*/
extern mysql_mutex_t LOCK_open,
extern mysql_mutex_t
LOCK_user_locks, LOCK_status,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
@ -332,7 +332,7 @@ extern mysql_cond_t COND_server_started;
extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern mysql_rwlock_t LOCK_system_variables_hash;
extern mysql_cond_t COND_thread_count;
extern mysql_cond_t COND_refresh, COND_manager;
extern mysql_cond_t COND_manager;
extern mysql_cond_t COND_global_read_lock;
extern int32 thread_running;
extern my_atomic_rwlock_t thread_running_lock;

View File

@ -95,20 +95,19 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
mysql_mutex_lock(&LOCK_open);
if (!(share= (get_table_share(thd, table_list, key, key_length, 0,
&error, hash_value))))
{
mysql_mutex_unlock(&LOCK_open);
share= get_table_share(thd, table_list, key, key_length, 0,
&error, hash_value);
mysql_mutex_unlock(&LOCK_open);
if (share == NULL)
DBUG_RETURN(0); // Can't open frm file
}
if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
{
mysql_mutex_lock(&LOCK_open);
release_table_share(share);
mysql_mutex_unlock(&LOCK_open);
DBUG_RETURN(0); // Out of memory
}
mysql_mutex_unlock(&LOCK_open);
table= &tmp_table;
}
@ -772,10 +771,8 @@ send_result_message:
}
else if (open_for_modify || fatal_error)
{
mysql_mutex_lock(&LOCK_open);
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table->db, table->table_name);
mysql_mutex_unlock(&LOCK_open);
table->db, table->table_name, FALSE);
/*
May be something modified. Consequently, we have to
invalidate the query cache.

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,7 @@ enum enum_tdc_remove_table_type {TDC_RT_REMOVE_ALL, TDC_RT_REMOVE_NOT_OWN,
#define RTFC_CHECK_KILLED_FLAG 0x0004
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
extern mysql_mutex_t LOCK_open;
bool table_cache_init(void);
void table_cache_free(void);
bool table_def_init(void);
@ -88,21 +89,51 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
uint lock_flags);
/* mysql_lock_tables() and open_table() flags bits */
#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
#define MYSQL_LOCK_LOG_TABLE 0x0010
/**
Do not try to acquire a metadata lock on the table: we
already have one.
*/
#define MYSQL_OPEN_HAS_MDL_LOCK 0x0020
/**
If in locked tables mode, ignore the locked tables and get
a new instance of the table.
*/
#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
/** Don't look up the table in the list of temporary tables. */
#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
/** Fail instead of waiting when conficting metadata lock is discovered. */
#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200
/**
Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified
in parser.
*/
#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400
/**
When opening or locking the table, use the maximum timeout
(LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
*/
#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
/** Please refer to the internals manual. */
#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |\
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
MYSQL_LOCK_IGNORE_TIMEOUT |\
MYSQL_OPEN_GET_NEW_TABLE |\
MYSQL_OPEN_SKIP_TEMPORARY |\
MYSQL_OPEN_HAS_MDL_LOCK)
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
Open_table_context *ot_ctx);
bool name_lock_locked_table(THD *thd, TABLE_LIST *tables);
bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in);
TABLE *table_cache_insert_placeholder(THD *thd, const char *key,
uint key_length);
bool lock_table_name_if_not_cached(THD *thd, const char *db,
const char *table_name, TABLE **table);
void detach_merge_children(TABLE *table, bool clear_refs);
bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last,
TABLE_LIST *new_child_list, TABLE_LIST **new_last);
bool reopen_table(TABLE *table);
bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
void close_data_files_and_morph_locks(THD *thd, const char *db,
const char *table_name);
bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
@ -185,12 +216,9 @@ bool setup_tables_and_check_access(THD *thd,
ulong want_access);
bool wait_while_table_is_used(THD *thd, TABLE *table,
enum ha_extra_function function);
void unlink_open_table(THD *thd, TABLE *find, bool unlock);
void drop_open_table(THD *thd, TABLE *table, const char *db_name,
const char *table_name);
void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
bool remove_from_locked_tables);
void update_non_unique_table_error(TABLE_LIST *update,
const char *operation,
TABLE_LIST *duplicate);
@ -226,8 +254,6 @@ void close_temporary_table(THD *thd, TABLE *table, bool free_share,
void close_temporary(TABLE *table, bool free_share, bool delete_table);
bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
const char *table_name);
void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
void remove_db_from_cache(const char *db);
bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
/* Functions to work with system tables. */
@ -243,16 +269,15 @@ TABLE *open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
Open_tables_state *backup);
void close_performance_schema_table(THD *thd, Open_tables_state *backup);
bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
bool wait_for_refresh);
bool close_cached_connection_tables(THD *thd, bool wait_for_refresh,
LEX_STRING *connect_string,
bool have_lock = FALSE);
bool close_cached_tables(THD *thd, TABLE_LIST *tables,
bool wait_for_refresh, ulong timeout);
bool close_cached_connection_tables(THD *thd, LEX_STRING *connect_string);
void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
bool remove_from_locked_tables);
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
bool remove_table_from_cache(THD *thd, const char *db, const char *table,
uint flags);
void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
const char *db, const char *table_name);
const char *db, const char *table_name,
bool has_lock);
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
char *cache_key, uint cache_key_length,
MEM_ROOT *mem_root, uint flags);
@ -263,12 +288,10 @@ TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db,
void mark_tmp_table_for_reuse(TABLE *table);
bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists);
extern uint table_cache_count;
extern TABLE *unused_tables;
extern Item **not_found_item;
extern Field *not_found_field;
extern Field *view_ref_found;
extern HASH open_cache;
extern HASH table_def_cache;
/**
@ -446,8 +469,8 @@ public:
enum enum_open_table_action
{
OT_NO_ACTION= 0,
OT_MDL_CONFLICT,
OT_WAIT_TDC,
OT_BACKOFF_AND_RETRY,
OT_REOPEN_TABLES,
OT_DISCOVER,
OT_REPAIR
};
@ -457,9 +480,6 @@ public:
bool request_backoff_action(enum_open_table_action action_arg,
TABLE_LIST *table);
void add_request(MDL_request *request)
{ m_mdl_requests.push_front(request); }
bool can_recover_from_failed_open() const
{ return m_action != OT_NO_ACTION; }
@ -481,8 +501,6 @@ public:
uint get_flags() const { return m_flags; }
private:
/** List of requests for all locks taken so far. Used for waiting on locks. */
MDL_request_list m_mdl_requests;
/**
For OT_DISCOVER and OT_REPAIR actions, the table list element for
the table which definition should be re-discovered or which
@ -508,4 +526,34 @@ private:
};
/**
This internal handler is used to trap ER_NO_SUCH_TABLE.
*/
class No_such_table_error_handler : public Internal_error_handler
{
public:
No_such_table_error_handler()
: m_handled_errors(0), m_unhandled_errors(0)
{}
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg,
MYSQL_ERROR ** cond_hdl);
/**
Returns TRUE if one or more ER_NO_SUCH_TABLE errors have been
trapped and no other errors have been seen. FALSE otherwise.
*/
bool safely_trapped_errors();
private:
int m_handled_errors;
int m_unhandled_errors;
};
#endif /* SQL_BASE_INCLUDED */

View File

@ -934,7 +934,7 @@ void mysql_ha_flush(THD *thd)
((hash_tables->table->mdl_ticket &&
hash_tables->table->mdl_ticket->has_pending_conflicting_lock()) ||
(!hash_tables->table->s->tmp_table &&
hash_tables->table->s->needs_reopen())))
hash_tables->table->s->has_old_version())))
mysql_ha_close_table(thd, hash_tables);
}

View File

@ -2705,7 +2705,7 @@ bool Delayed_insert::handle_inserts(void)
thd_proc_info(&thd, "insert");
max_rows= delayed_insert_limit;
if (thd.killed || table->s->needs_reopen())
if (thd.killed || table->s->has_old_version())
{
thd.killed= THD::KILL_CONNECTION;
max_rows= ULONG_MAX; // Do as much as possible
@ -3592,11 +3592,9 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
*/
if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
{
mysql_mutex_lock(&LOCK_open);
quick_rm_table(create_info->db_type, create_table->db,
table_case_name(create_info, create_table->table_name),
0);
mysql_mutex_unlock(&LOCK_open);
}
else
table= create_table->table;

View File

@ -50,6 +50,7 @@
// mysql_backup_table,
// mysql_restore_table
#include "sql_truncate.h" // mysql_truncate_table
#include "sql_reload.h" // reload_acl_and_cache
#include "sql_admin.h" // mysql_assign_to_keycache
#include "sql_connect.h" // check_user,
// decrease_user_connections,
@ -1695,140 +1696,6 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
}
/**
Implementation of FLUSH TABLES <table_list> WITH READ LOCK.
In brief: take exclusive locks, expel tables from the table
cache, reopen the tables, enter the 'LOCKED TABLES' mode,
downgrade the locks.
Note: the function is written to be called from
mysql_execute_command(), it is not reusable in arbitrary
execution context.
Required privileges
-------------------
Since the statement implicitly enters LOCK TABLES mode,
it requires LOCK TABLES privilege on every table.
But since the rest of FLUSH commands require
the global RELOAD_ACL, it also requires RELOAD_ACL.
Compatibility with the global read lock
---------------------------------------
We don't wait for the GRL, since neither the
5.1 combination that this new statement is intended to
replace (LOCK TABLE <list> WRITE; FLUSH TABLES;),
nor FLUSH TABLES WITH READ LOCK do.
@todo: this is not implemented, Dmitry disagrees.
Currently we wait for GRL in another connection,
but are compatible with a GRL in our own connection.
Behaviour under LOCK TABLES
---------------------------
Bail out: i.e. don't perform an implicit UNLOCK TABLES.
This is not consistent with LOCK TABLES statement, but is
in line with behaviour of FLUSH TABLES WITH READ LOCK, and we
try to not introduce any new statements with implicit
semantics.
Compatibility with parallel updates
-----------------------------------
As a result, we will wait for all open transactions
against the tables to complete. After the lock downgrade,
new transactions will be able to read the tables, but not
write to them.
Differences from FLUSH TABLES <list>
-------------------------------------
- you can't flush WITH READ LOCK a non-existent table
- you can't flush WITH READ LOCK under LOCK TABLES
- currently incompatible with the GRL (@todo: fix)
Effect on views and temporary tables.
------------------------------------
You can only apply this command to existing base tables.
If a view with such name exists, ER_WRONG_OBJECT is returned.
If a temporary table with such name exists, it's ignored:
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
is returned.
*/
static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
TABLE_LIST *table_list;
/*
This is called from SQLCOM_FLUSH, the transaction has
been committed implicitly.
*/
/* RELOAD_ACL is checked by the caller. Check table-level privileges. */
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error;
if (thd->locked_tables_mode)
{
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
goto error;
}
/*
@todo: Since lock_table_names() acquires a global IX
lock, this actually waits for a GRL in another connection.
We are thus introducing an incompatibility.
Do nothing for now, since not taking a global IX violates
current internal MDL asserts, fix after discussing with
Dmitry.
*/
if (lock_table_names(thd, all_tables, 0, thd->variables.lock_wait_timeout,
MYSQL_OPEN_SKIP_TEMPORARY))
goto error;
for (table_list= all_tables; table_list;
table_list= table_list->next_global)
{
/* Remove the table from cache. */
mysql_mutex_lock(&LOCK_open);
tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
table_list->db,
table_list->table_name);
mysql_mutex_unlock(&LOCK_open);
/* Skip views and temporary tables. */
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
}
if (open_and_lock_tables(thd, all_tables, FALSE,
MYSQL_OPEN_HAS_MDL_LOCK,
&lock_tables_prelocking_strategy) ||
thd->locked_tables_list.init_locked_tables(thd))
{
goto error;
}
thd->variables.option_bits|= OPTION_TABLE_LOCK;
/*
Downgrade the exclusive locks.
Use MDL_SHARED_NO_WRITE as the intended
post effect of this call is identical
to LOCK TABLES <...> READ, and we didn't use
thd->in_lock_talbes and thd->sql_command= SQLCOM_LOCK_TABLES
hacks to enter the LTM.
@todo: release the global IX lock here!!!
*/
for (table_list= all_tables; table_list;
table_list= table_list->next_global)
table_list->mdl_request.ticket->downgrade_exclusive_lock(MDL_SHARED_NO_WRITE);
return FALSE;
error:
return TRUE;
}
/**
Read query from packet and store in thd->query.
Used in COM_QUERY and COM_STMT_PREPARE.
@ -3226,7 +3093,7 @@ end_with_restore_list:
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->variables.option_bits|= OPTION_KEEP_LOG;
}
/* DDL and binlog write order protected by LOCK_open */
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
}
@ -3771,6 +3638,10 @@ end_with_restore_list:
if (first_table && lex->type & REFRESH_READ_LOCK)
{
/* Check table-level privileges. */
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error;
if (flush_tables_with_read_lock(thd, all_tables))
goto error;
my_ok(thd);
@ -6511,258 +6382,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
}
/**
Reload/resets privileges and the different caches.
@param thd Thread handler (can be NULL!)
@param options What should be reset/reloaded (tables, privileges, slave...)
@param tables Tables to flush (if any)
@param write_to_binlog True if we can write to the binlog.
@note Depending on 'options', it may be very bad to write the
query to the binlog (e.g. FLUSH SLAVE); this is a
pointer where reload_acl_and_cache() will put 0 if
it thinks we really should not write to the binlog.
Otherwise it will put 1.
@return Error status code
@retval 0 Ok
@retval !=0 Error; thd->killed is set or thd->is_error() is true
*/
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
bool *write_to_binlog)
{
bool result=0;
select_errors=0; /* Write if more errors */
bool tmp_write_to_binlog= 1;
DBUG_ASSERT(!thd || !thd->in_sub_stmt);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_GRANT)
{
THD *tmp_thd= 0;
/*
If reload_acl_and_cache() is called from SIGHUP handler we have to
allocate temporary THD for execution of acl_reload()/grant_reload().
*/
if (!thd && (thd= (tmp_thd= new THD)))
{
thd->thread_stack= (char*) &tmp_thd;
thd->store_globals();
}
if (thd)
{
bool reload_acl_failed= acl_reload(thd);
bool reload_grants_failed= grant_reload(thd);
bool reload_servers_failed= servers_reload(thd);
if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
{
result= 1;
/*
When an error is returned, my_message may have not been called and
the client will hang waiting for a response.
*/
my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
}
}
if (tmp_thd)
{
delete tmp_thd;
/* Remember that we don't have a THD */
my_pthread_setspecific_ptr(THR_THD, 0);
thd= 0;
}
reset_mqh((LEX_USER *)NULL, TRUE);
}
#endif
if (options & REFRESH_LOG)
{
/*
Flush the normal query log, the update log, the binary log,
the slow query log, the relay log (if it exists) and the log
tables.
*/
options|= REFRESH_BINARY_LOG;
options|= REFRESH_RELAY_LOG;
options|= REFRESH_SLOW_LOG;
options|= REFRESH_GENERAL_LOG;
options|= REFRESH_ENGINE_LOG;
options|= REFRESH_ERROR_LOG;
}
if (options & REFRESH_ERROR_LOG)
if (flush_error_log())
result= 1;
if ((options & REFRESH_SLOW_LOG) && opt_slow_log)
logger.flush_slow_log();
if ((options & REFRESH_GENERAL_LOG) && opt_log)
logger.flush_general_log();
if (options & REFRESH_ENGINE_LOG)
if (ha_flush_logs(NULL))
result= 1;
if (options & REFRESH_BINARY_LOG)
{
/*
Writing this command to the binlog may result in infinite loops
when doing mysqlbinlog|mysql, and anyway it does not really make
sense to log it automatically (would cause more trouble to users
than it would help them)
*/
tmp_write_to_binlog= 0;
if (mysql_bin_log.is_open())
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
}
if (options & REFRESH_RELAY_LOG)
{
#ifdef HAVE_REPLICATION
mysql_mutex_lock(&LOCK_active_mi);
rotate_relay_log(active_mi);
mysql_mutex_unlock(&LOCK_active_mi);
#endif
}
#ifdef HAVE_QUERY_CACHE
if (options & REFRESH_QUERY_CACHE_FREE)
{
query_cache.pack(); // FLUSH QUERY CACHE
options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
}
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
{
query_cache.flush(); // RESET QUERY CACHE
}
#endif /*HAVE_QUERY_CACHE*/
DBUG_ASSERT(!thd || thd->locked_tables_mode ||
!thd->mdl_context.has_locks() ||
thd->handler_tables_hash.records ||
thd->global_read_lock.is_acquired());
/*
Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
(see sql_yacc.yy)
*/
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
if ((options & REFRESH_READ_LOCK) && thd)
{
/*
On the first hand we need write lock on the tables to be flushed,
on the other hand we must not try to aspire a global read lock
if we have a write locked table as this would lead to a deadlock
when trying to reopen (and re-lock) the table after the flush.
*/
if (thd->locked_tables_mode)
{
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
return 1;
}
/*
Writing to the binlog could cause deadlocks, as we don't log
UNLOCK TABLES
*/
tmp_write_to_binlog= 0;
if (thd->global_read_lock.lock_global_read_lock(thd))
return 1; // Killed
if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
FALSE : TRUE))
result= 1;
if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed
{
/* Don't leave things in a half-locked state */
thd->global_read_lock.unlock_global_read_lock(thd);
return 1;
}
}
else
{
if (thd && thd->locked_tables_mode)
{
/*
If we are under LOCK TABLES we should have a write
lock on tables which we are going to flush.
*/
if (tables)
{
for (TABLE_LIST *t= tables; t; t= t->next_local)
if (!find_table_for_mdl_upgrade(thd->open_tables, t->db,
t->table_name, FALSE))
return 1;
}
else
{
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
{
if (! tab->mdl_ticket->is_upgradable_or_exclusive())
{
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
tab->s->table_name.str);
return 1;
}
}
}
}
if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
FALSE : TRUE))
result= 1;
}
my_dbopt_cleanup();
}
if (options & REFRESH_HOSTS)
hostname_cache_refresh();
if (thd && (options & REFRESH_STATUS))
refresh_status(thd);
if (options & REFRESH_THREADS)
flush_thread_cache();
#ifdef HAVE_REPLICATION
if (options & REFRESH_MASTER)
{
DBUG_ASSERT(thd);
tmp_write_to_binlog= 0;
if (reset_master(thd))
{
result=1;
}
}
#endif
#ifdef OPENSSL
if (options & REFRESH_DES_KEY_FILE)
{
if (des_key_file && load_des_key_file(des_key_file))
result= 1;
}
#endif
#ifdef HAVE_REPLICATION
if (options & REFRESH_SLAVE)
{
tmp_write_to_binlog= 0;
mysql_mutex_lock(&LOCK_active_mi);
if (reset_slave(thd, active_mi))
result=1;
mysql_mutex_unlock(&LOCK_active_mi);
}
#endif
if (options & REFRESH_USER_RESOURCES)
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
/*
If the query was killed then this function must fail.
*/
return result || (thd ? thd->killed : 0);
}
/**
kill on thread.

View File

@ -93,8 +93,6 @@ void mysql_init_multi_delete(LEX *lex);
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void create_table_set_open_action_and_adjust_tables(LEX *lex);
pthread_handler_t handle_bootstrap(void *arg);
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
bool *write_to_binlog);
int mysql_execute_command(THD *thd);
bool do_command(THD *thd);
void do_handle_bootstrap(THD *thd);

View File

@ -6342,7 +6342,7 @@ static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
*/
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table->s->db.str,
table->s->table_name.str);
table->s->table_name.str, TRUE);
}
}
mysql_mutex_unlock(&LOCK_open);

View File

@ -1393,8 +1393,9 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
READ_RECORD read_record_info;
int error;
THD *new_thd= &thd;
bool result;
#ifdef EMBEDDED_LIBRARY
bool table_exists;
No_such_table_error_handler error_handler;
#endif /* EMBEDDED_LIBRARY */
DBUG_ENTER("plugin_load");
@ -1410,13 +1411,18 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
When building an embedded library, if the mysql.plugin table
does not exist, we silently ignore the missing table
*/
if (check_if_table_exists(new_thd, &tables, &table_exists))
table_exists= FALSE;
if (!table_exists)
new_thd->push_internal_handler(&error_handler);
#endif /* EMBEDDED_LIBRARY */
result= open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT);
#ifdef EMBEDDED_LIBRARY
new_thd->pop_internal_handler();
if (error_handler.safely_trapped_errors())
goto end;
#endif /* EMBEDDED_LIBRARY */
if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
if (result)
{
DBUG_PRINT("error",("Can't open plugin table"));
sql_print_error("Can't open the mysql.plugin table. Please "

427
sql/sql_reload.cc Normal file
View File

@ -0,0 +1,427 @@
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql_reload.h"
#include "sql_priv.h"
#include "mysqld.h" // select_errors
#include "sql_class.h" // THD
#include "sql_acl.h" // acl_reload
#include "sql_servers.h" // servers_reload
#include "sql_connect.h" // reset_mqh
#include "sql_base.h" // close_cached_tables
#include "sql_db.h" // my_dbopt_cleanup
#include "hostname.h" // hostname_cache_refresh
#include "sql_repl.h" // reset_master, reset_slave
#include "debug_sync.h"
/**
Reload/resets privileges and the different caches.
@param thd Thread handler (can be NULL!)
@param options What should be reset/reloaded (tables, privileges, slave...)
@param tables Tables to flush (if any)
@param write_to_binlog True if we can write to the binlog.
@note Depending on 'options', it may be very bad to write the
query to the binlog (e.g. FLUSH SLAVE); this is a
pointer where reload_acl_and_cache() will put 0 if
it thinks we really should not write to the binlog.
Otherwise it will put 1.
@return Error status code
@retval 0 Ok
@retval !=0 Error; thd->killed is set or thd->is_error() is true
*/
bool reload_acl_and_cache(THD *thd, unsigned long options,
TABLE_LIST *tables, bool *write_to_binlog)
{
bool result=0;
select_errors=0; /* Write if more errors */
bool tmp_write_to_binlog= 1;
DBUG_ASSERT(!thd || !thd->in_sub_stmt);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_GRANT)
{
THD *tmp_thd= 0;
/*
If reload_acl_and_cache() is called from SIGHUP handler we have to
allocate temporary THD for execution of acl_reload()/grant_reload().
*/
if (!thd && (thd= (tmp_thd= new THD)))
{
thd->thread_stack= (char*) &tmp_thd;
thd->store_globals();
}
if (thd)
{
bool reload_acl_failed= acl_reload(thd);
bool reload_grants_failed= grant_reload(thd);
bool reload_servers_failed= servers_reload(thd);
if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
{
result= 1;
/*
When an error is returned, my_message may have not been called and
the client will hang waiting for a response.
*/
my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
}
}
if (tmp_thd)
{
delete tmp_thd;
/* Remember that we don't have a THD */
my_pthread_setspecific_ptr(THR_THD, 0);
thd= 0;
}
reset_mqh((LEX_USER *)NULL, TRUE);
}
#endif
if (options & REFRESH_LOG)
{
/*
Flush the normal query log, the update log, the binary log,
the slow query log, the relay log (if it exists) and the log
tables.
*/
options|= REFRESH_BINARY_LOG;
options|= REFRESH_RELAY_LOG;
options|= REFRESH_SLOW_LOG;
options|= REFRESH_GENERAL_LOG;
options|= REFRESH_ENGINE_LOG;
options|= REFRESH_ERROR_LOG;
}
if (options & REFRESH_ERROR_LOG)
if (flush_error_log())
result= 1;
if ((options & REFRESH_SLOW_LOG) && opt_slow_log)
logger.flush_slow_log();
if ((options & REFRESH_GENERAL_LOG) && opt_log)
logger.flush_general_log();
if (options & REFRESH_ENGINE_LOG)
if (ha_flush_logs(NULL))
result= 1;
if (options & REFRESH_BINARY_LOG)
{
/*
Writing this command to the binlog may result in infinite loops
when doing mysqlbinlog|mysql, and anyway it does not really make
sense to log it automatically (would cause more trouble to users
than it would help them)
*/
tmp_write_to_binlog= 0;
if (mysql_bin_log.is_open())
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
}
if (options & REFRESH_RELAY_LOG)
{
#ifdef HAVE_REPLICATION
mysql_mutex_lock(&LOCK_active_mi);
rotate_relay_log(active_mi);
mysql_mutex_unlock(&LOCK_active_mi);
#endif
}
#ifdef HAVE_QUERY_CACHE
if (options & REFRESH_QUERY_CACHE_FREE)
{
query_cache.pack(); // FLUSH QUERY CACHE
options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
}
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
{
query_cache.flush(); // RESET QUERY CACHE
}
#endif /*HAVE_QUERY_CACHE*/
DBUG_ASSERT(!thd || thd->locked_tables_mode ||
!thd->mdl_context.has_locks() ||
thd->handler_tables_hash.records ||
thd->global_read_lock.is_acquired());
/*
Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
(see sql_yacc.yy)
*/
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
if ((options & REFRESH_READ_LOCK) && thd)
{
/*
On the first hand we need write lock on the tables to be flushed,
on the other hand we must not try to aspire a global read lock
if we have a write locked table as this would lead to a deadlock
when trying to reopen (and re-lock) the table after the flush.
*/
if (thd->locked_tables_mode)
{
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
return 1;
}
/*
Writing to the binlog could cause deadlocks, as we don't log
UNLOCK TABLES
*/
tmp_write_to_binlog= 0;
if (thd->global_read_lock.lock_global_read_lock(thd))
return 1; // Killed
if (close_cached_tables(thd, tables,
((options & REFRESH_FAST) ? FALSE : TRUE),
thd->variables.lock_wait_timeout))
result= 1;
if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed
{
/* Don't leave things in a half-locked state */
thd->global_read_lock.unlock_global_read_lock(thd);
return 1;
}
}
else
{
if (thd && thd->locked_tables_mode)
{
/*
If we are under LOCK TABLES we should have a write
lock on tables which we are going to flush.
*/
if (tables)
{
for (TABLE_LIST *t= tables; t; t= t->next_local)
if (!find_table_for_mdl_upgrade(thd->open_tables, t->db,
t->table_name, FALSE))
return 1;
}
else
{
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
{
if (! tab->mdl_ticket->is_upgradable_or_exclusive())
{
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
tab->s->table_name.str);
return 1;
}
}
}
}
if (close_cached_tables(thd, tables,
((options & REFRESH_FAST) ? FALSE : TRUE),
(thd ? thd->variables.lock_wait_timeout :
LONG_TIMEOUT)))
result= 1;
}
my_dbopt_cleanup();
}
if (options & REFRESH_HOSTS)
hostname_cache_refresh();
if (thd && (options & REFRESH_STATUS))
refresh_status(thd);
if (options & REFRESH_THREADS)
flush_thread_cache();
#ifdef HAVE_REPLICATION
if (options & REFRESH_MASTER)
{
DBUG_ASSERT(thd);
tmp_write_to_binlog= 0;
if (reset_master(thd))
{
result=1;
}
}
#endif
#ifdef OPENSSL
if (options & REFRESH_DES_KEY_FILE)
{
if (des_key_file && load_des_key_file(des_key_file))
result= 1;
}
#endif
#ifdef HAVE_REPLICATION
if (options & REFRESH_SLAVE)
{
tmp_write_to_binlog= 0;
mysql_mutex_lock(&LOCK_active_mi);
if (reset_slave(thd, active_mi))
result=1;
mysql_mutex_unlock(&LOCK_active_mi);
}
#endif
if (options & REFRESH_USER_RESOURCES)
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
/*
If the query was killed then this function must fail.
*/
return result || (thd ? thd->killed : 0);
}
/**
Implementation of FLUSH TABLES <table_list> WITH READ LOCK.
In brief: take exclusive locks, expel tables from the table
cache, reopen the tables, enter the 'LOCKED TABLES' mode,
downgrade the locks.
Note: the function is written to be called from
mysql_execute_command(), it is not reusable in arbitrary
execution context.
Required privileges
-------------------
Since the statement implicitly enters LOCK TABLES mode,
it requires LOCK TABLES privilege on every table.
But since the rest of FLUSH commands require
the global RELOAD_ACL, it also requires RELOAD_ACL.
Compatibility with the global read lock
---------------------------------------
We don't wait for the GRL, since neither the
5.1 combination that this new statement is intended to
replace (LOCK TABLE <list> WRITE; FLUSH TABLES;),
nor FLUSH TABLES WITH READ LOCK do.
@todo: this is not implemented, Dmitry disagrees.
Currently we wait for GRL in another connection,
but are compatible with a GRL in our own connection.
Behaviour under LOCK TABLES
---------------------------
Bail out: i.e. don't perform an implicit UNLOCK TABLES.
This is not consistent with LOCK TABLES statement, but is
in line with behaviour of FLUSH TABLES WITH READ LOCK, and we
try to not introduce any new statements with implicit
semantics.
Compatibility with parallel updates
-----------------------------------
As a result, we will wait for all open transactions
against the tables to complete. After the lock downgrade,
new transactions will be able to read the tables, but not
write to them.
Differences from FLUSH TABLES <list>
-------------------------------------
- you can't flush WITH READ LOCK a non-existent table
- you can't flush WITH READ LOCK under LOCK TABLES
- currently incompatible with the GRL (@todo: fix)
Effect on views and temporary tables.
------------------------------------
You can only apply this command to existing base tables.
If a view with such name exists, ER_WRONG_OBJECT is returned.
If a temporary table with such name exists, it's ignored:
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
is returned.
Implicit commit
---------------
This statement causes an implicit commit before and
after it.
HANDLER SQL
-----------
If this connection has HANDLERs open against
some of the tables being FLUSHed, these handlers
are implicitly flushed (lose their position).
*/
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
TABLE_LIST *table_list;
MDL_request_list mdl_requests;
/*
This is called from SQLCOM_FLUSH, the transaction has
been committed implicitly.
*/
if (thd->locked_tables_mode)
{
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
goto error;
}
/*
Acquire SNW locks on tables to be flushed. We can't use
lock_table_names() here as this call will also acquire global IX
and database-scope IX locks on the tables, and this will make
this statement incompatible with FLUSH TABLES WITH READ LOCK.
*/
for (table_list= all_tables; table_list;
table_list= table_list->next_global)
mdl_requests.push_front(&table_list->mdl_request);
if (thd->mdl_context.acquire_locks(&mdl_requests,
thd->variables.lock_wait_timeout))
goto error;
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
for (table_list= all_tables; table_list;
table_list= table_list->next_global)
{
/* Request removal of table from cache. */
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table_list->db,
table_list->table_name, FALSE);
/* Skip views and temporary tables. */
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
}
/*
Before opening and locking tables the below call also waits
for old shares to go away, so the fact that we don't pass
MYSQL_LOCK_IGNORE_FLUSH flag to it is important.
*/
if (open_and_lock_tables(thd, all_tables, FALSE,
MYSQL_OPEN_HAS_MDL_LOCK,
&lock_tables_prelocking_strategy) ||
thd->locked_tables_list.init_locked_tables(thd))
{
goto error;
}
thd->variables.option_bits|= OPTION_TABLE_LOCK;
/*
We don't downgrade MDL_SHARED_NO_WRITE here as the intended
post effect of this call is identical to LOCK TABLES <...> READ,
and we didn't use thd->in_lock_talbes and
thd->sql_command= SQLCOM_LOCK_TABLES hacks to enter the LTM.
*/
return FALSE;
error:
return TRUE;
}

26
sql/sql_reload.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef SQL_RELOAD_INCLUDED
#define SQL_RELOAD_INCLUDED
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
class THD;
struct TABLE_LIST;
bool reload_acl_and_cache(THD *thd, unsigned long options,
TABLE_LIST *tables, bool *write_to_binlog);
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables);
#endif

View File

@ -147,13 +147,15 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
MYSQL_OPEN_SKIP_TEMPORARY))
goto err;
mysql_mutex_lock(&LOCK_open);
for (ren_table= table_list; ren_table; ren_table= ren_table->next_local)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, ren_table->db,
ren_table->table_name);
ren_table->table_name, FALSE);
error=0;
/*
An exclusive lock on table names is satisfactory to ensure
no other thread accesses this table.
*/
if ((ren_table=rename_tables(thd,table_list,0)))
{
/* Rename didn't succeed; rename back the tables in reverse order */
@ -175,17 +177,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
error= 1;
}
/*
An exclusive lock on table names is satisfactory to ensure
no other thread accesses this table.
However, NDB assumes that handler::rename_tables is called under
LOCK_open. And it indeed is, from ALTER TABLE.
TODO: remove this limitation.
We still should unlock LOCK_open as early as possible, to provide
higher concurrency - query_cache_invalidate can take minutes to
complete.
*/
mysql_mutex_unlock(&LOCK_open);
if (!silent && !error)
{
@ -197,8 +188,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
if (!error)
query_cache_invalidate3(thd, table_list, 0);
thd->mdl_context.release_transactional_locks();
err:
thd->global_read_lock.start_waiting_global_read_lock(thd);
DBUG_RETURN(error || binlog_error);

View File

@ -628,7 +628,7 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
/* close the servers table before we call closed_cached_connection_tables */
close_mysql_tables(thd);
if (close_cached_connection_tables(thd, TRUE, &name))
if (close_cached_connection_tables(thd, &name))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, "Server connection in use");
@ -1057,7 +1057,7 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
/* close the servers table before we call closed_cached_connection_tables */
close_mysql_tables(thd);
if (close_cached_connection_tables(thd, FALSE, &name))
if (close_cached_connection_tables(thd, &name))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, "Server connection in use");

View File

@ -3273,8 +3273,8 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
/*
TODO: investigate if in this particular situation we can get by
simply obtaining internal lock of data-dictionary (ATM it
is LOCK_open) instead of obtaning full-blown metadata lock.
simply obtaining internal lock of the data-dictionary
instead of obtaining full-blown metadata lock.
*/
if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
{
@ -7657,7 +7657,7 @@ static bool show_create_trigger_impl(THD *thd,
*/
static
TABLE_LIST *get_trigger_table_impl(THD *thd, const sp_name *trg_name)
TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
{
char trn_path_buff[FN_REFLEN];
LEX_STRING trn_path= { trn_path_buff, 0 };
@ -7694,39 +7694,6 @@ TABLE_LIST *get_trigger_table_impl(THD *thd, const sp_name *trg_name)
return table;
}
/**
Read TRN and TRG files to obtain base table name for the specified
trigger name and construct TABE_LIST object for the base table. Acquire
LOCK_open when doing this.
@param thd Thread context.
@param trg_name Trigger name.
@return TABLE_LIST object corresponding to the base table.
*/
static
TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
{
/* Acquire LOCK_open (stop the server). */
mysql_mutex_lock(&LOCK_open);
/*
Load base table name from the TRN-file and create TABLE_LIST object.
*/
TABLE_LIST *lst= get_trigger_table_impl(thd, trg_name);
/* Release LOCK_open (continue the server). */
mysql_mutex_unlock(&LOCK_open);
/* That's it. */
return lst;
}
/**
SHOW CREATE TRIGGER high-level implementation.

View File

@ -1719,7 +1719,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
completing this we write a new phase to the log entry that will
deactivate it.
*/
mysql_mutex_lock(&LOCK_open);
if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
#ifdef WITH_PARTITION_STORAGE_ENGINE
lpt->table->file->ha_create_handler_files(path, shadow_path,
@ -1775,12 +1774,12 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
#endif
err:
mysql_mutex_unlock(&LOCK_open);
#ifdef WITH_PARTITION_STORAGE_ENGINE
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
part_info->frm_log_entry= NULL;
(void) sync_ddl_log();
#endif
;
}
end:
@ -1999,10 +1998,11 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
MYSQL_OPEN_SKIP_TEMPORARY))
DBUG_RETURN(1);
mysql_mutex_lock(&LOCK_open);
for (table= tables; table; table= table->next_local)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
mysql_mutex_unlock(&LOCK_open);
{
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
FALSE);
}
}
else
{
@ -2171,15 +2171,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
built_query.append("`,");
}
}
/*
TODO: Investigate what should be done to remove this lock completely.
Is exclusive meta-data lock enough ?
*/
DEBUG_SYNC(thd, "rm_table_part2_before_delete_table");
DBUG_EXECUTE_IF("sleep_before_part2_delete_table",
my_sleep(100000););
mysql_mutex_lock(&LOCK_open);
error= 0;
if (drop_temporary ||
((access(path, F_OK) &&
@ -2209,8 +2203,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
char *end;
/*
Cannot use the db_type from the table, since that might have changed
while waiting for the exclusive name lock. We are under LOCK_open,
so reading from the frm-file is safe.
while waiting for the exclusive name lock.
*/
if (frm_db_type == DB_TYPE_UNKNOWN)
{
@ -2252,7 +2245,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
non_tmp_error= error ? TRUE : non_tmp_error;
}
mysql_mutex_unlock(&LOCK_open);
if (error)
{
if (wrong_tables.length())
@ -4098,7 +4090,6 @@ bool mysql_create_table_no_lock(THD *thd,
goto err;
}
mysql_mutex_lock(&LOCK_open);
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
if (!access(path,F_OK))
@ -4106,7 +4097,7 @@ bool mysql_create_table_no_lock(THD *thd,
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
goto unlock_and_end;
goto err;
}
/*
We don't assert here, but check the result, because the table could be
@ -4116,11 +4107,14 @@ bool mysql_create_table_no_lock(THD *thd,
Then she could create the table. This case is pretty obscure and
therefore we don't introduce a new error message only for it.
*/
mysql_mutex_lock(&LOCK_open);
if (get_cached_table_share(db, table_name))
{
mysql_mutex_unlock(&LOCK_open);
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
goto unlock_and_end;
goto err;
}
mysql_mutex_unlock(&LOCK_open);
}
/*
@ -4128,7 +4122,7 @@ bool mysql_create_table_no_lock(THD *thd,
exist in any storage engine. In such a case it should
be discovered and the error ER_TABLE_EXISTS_ERROR be returned
unless user specified CREATE TABLE IF EXISTS
The LOCK_open mutex has been locked to make sure no
An exclusive metadata lock ensures that no
one else is attempting to discover the table. Since
it's not on disk as a frm file, no one could be using it!
*/
@ -4149,12 +4143,12 @@ bool mysql_create_table_no_lock(THD *thd,
if (create_if_not_exists)
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
goto unlock_and_end;
goto err;
break;
default:
DBUG_PRINT("info", ("error: %u from storage engine", retcode));
my_error(retcode, MYF(0),table_name);
goto unlock_and_end;
goto err;
}
}
@ -4186,7 +4180,7 @@ bool mysql_create_table_no_lock(THD *thd,
if (test_if_data_home_dir(dirpath))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
goto unlock_and_end;
goto err;
}
}
if (create_info->index_file_name)
@ -4195,7 +4189,7 @@ bool mysql_create_table_no_lock(THD *thd,
if (test_if_data_home_dir(dirpath))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
goto unlock_and_end;
goto err;
}
}
}
@ -4203,7 +4197,7 @@ bool mysql_create_table_no_lock(THD *thd,
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (check_partition_dirs(thd->lex->part_info))
{
goto unlock_and_end;
goto err;
}
#endif /* WITH_PARTITION_STORAGE_ENGINE */
@ -4226,7 +4220,7 @@ bool mysql_create_table_no_lock(THD *thd,
if (rea_create_table(thd, path, db, table_name,
create_info, alter_info->create_list,
key_count, key_info_buffer, file))
goto unlock_and_end;
goto err;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
@ -4235,7 +4229,7 @@ bool mysql_create_table_no_lock(THD *thd,
if (!(table= open_temporary_table(thd, path, db, table_name, 1)))
{
(void) rm_temporary_table(create_info->db_type, path);
goto unlock_and_end;
goto err;
}
if (is_trans != NULL)
@ -4245,9 +4239,6 @@ bool mysql_create_table_no_lock(THD *thd,
}
error= FALSE;
unlock_and_end:
mysql_mutex_unlock(&LOCK_open);
err:
thd_proc_info(thd, "After create");
delete file;
@ -4258,7 +4249,7 @@ warn:
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
goto unlock_and_end;
goto err;
}
@ -5920,7 +5911,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
else
{
*fn_ext(new_name)=0;
mysql_mutex_lock(&LOCK_open);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
error= -1;
else if (Table_triggers_list::change_table_name(thd, db, table_name,
@ -5930,7 +5920,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
table_name, 0);
error= -1;
}
mysql_mutex_unlock(&LOCK_open);
}
}
@ -6549,7 +6538,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* This type cannot happen in regular ALTER. */
new_db_type= old_db_type= NULL;
}
mysql_mutex_lock(&LOCK_open);
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
FN_TO_IS_TMP))
{
@ -6576,8 +6564,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (! error)
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
mysql_mutex_unlock(&LOCK_open);
if (error)
{
/* This shouldn't happen. But let us play it safe. */
@ -7192,4 +7178,3 @@ static bool check_engine(THD *thd, const char *table_name,
}
return FALSE;
}

View File

@ -118,7 +118,7 @@ static void print_cached_tables(void)
printf("unused_links isn't linked properly\n");
return;
}
} while (count++ < table_cache_count && (lnk=lnk->next) != start_link);
} while (count++ < cached_open_tables() && (lnk=lnk->next) != start_link);
if (lnk != start_link)
{
printf("Unused_links aren't connected\n");
@ -416,7 +416,7 @@ static void display_table_locks(void)
void *saved_base;
DYNAMIC_ARRAY saved_table_locks;
(void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), table_cache_count + 20,50);
(void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), cached_open_tables() + 20,50);
mysql_mutex_lock(&THR_LOCK_lock);
for (list= thr_lock_thread_list; list; list= list_rest(list))
{

View File

@ -394,9 +394,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
/*
We don't want perform our operations while global read lock is held
so we have to wait until its end and then prevent it from occurring
again until we are done, unless we are under lock tables. (Acquiring
LOCK_open is not enough because global read lock is held without holding
LOCK_open).
again until we are done, unless we are under lock tables.
*/
if (!thd->locked_tables_mode &&
thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
@ -516,11 +514,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
goto end;
}
mysql_mutex_lock(&LOCK_open);
result= (create ?
table->triggers->create_trigger(thd, tables, &stmt_query):
table->triggers->drop_trigger(thd, tables, &stmt_query));
mysql_mutex_unlock(&LOCK_open);
if (result)
goto end;
@ -1680,9 +1676,6 @@ bool add_table_for_trigger(THD *thd,
@param db schema for table
@param name name for table
@note
The calling thread should hold the LOCK_open mutex;
@retval
False success
@retval
@ -1912,14 +1905,10 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
/*
This method interfaces the mysql server code protected by
either LOCK_open mutex or with an exclusive metadata lock.
In the future, only an exclusive metadata lock will be enough.
an exclusive metadata lock.
*/
#ifndef DBUG_OFF
if (thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, old_table,
MDL_EXCLUSIVE))
mysql_mutex_assert_owner(&LOCK_open);
#endif
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, old_table,
MDL_EXCLUSIVE));
DBUG_ASSERT(my_strcasecmp(table_alias_charset, db, new_db) ||
my_strcasecmp(table_alias_charset, old_table, new_table));

Some files were not shown because too many files have changed in this diff Show More