diff options
64 files changed, 1201 insertions, 275 deletions
diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 7fcaaa9aa09..cb377e16ce4 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-next-mr" +tree_name = "mysql-next-mr-bugfixing" diff --git a/CMakeLists.txt b/CMakeLists.txt index 036d0cdb9d6..d20939f33ac 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,26 +32,32 @@ IF(DEFINED CMAKE_BUILD_TYPE) SET(HAVE_CMAKE_BUILD_TYPE TRUE) ENDIF() SET(CUSTOM_C_FLAGS $ENV{CFLAGS}) -IF(NOT CUSTOM_C_FLAGS) - SET(CUSTOM_C_FLAGS ${CMAKE_C_FLAGS}) -ENDIF() -OPTION(WITH_DEBUG "Use dbug" OFF) +OPTION(WITH_DEBUG "Use dbug/safemutex" OFF) OPTION(WITH_DEBUG_FULL "Use dbug and safemalloc/safemutex. Slow" OFF) -IF(NOT HAVE_CMAKE_BUILD_TYPE) - IF(BUILD_CONFIG OR NOT CUSTOM_C_FLAGS) - IF(WITH_DEBUG) - SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Debug build" FORCE) - ELSE() - SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING - "RelWithDebInfo build" FORCE) - ENDIF() - ENDIF() -ENDIF() -IF(WITH_DEBUG_FULL) - SET(WITH_DEBUG ON CACHE BOOL "Use DBUG") +# We choose to provide WITH_DEBUG as alias to standard CMAKE_BUILD_TYPE=Debug +# which turns out to be not trivial, as this involves synchronization +# between CMAKE_BUILD_TYPE and WITH_DEBUG. Besides, we have to deal with cases +# where WITH_DEBUG is reset from ON to OFF and here we need to reset +# CMAKE_BUILD_TYPE to either none or default RelWithDebInfo + +SET(BUILDTYPE_DOCSTRING + "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or + CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel") + +IF(WITH_DEBUG OR WITH_DEBUG_FULL) + SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING ${BUILDTYPE_DOCSTRING} FORCE) + SET(OLD_WITH_DEBUG 1 CACHE INTERNAL "" FORCE) +ELSEIF(NOT HAVE_CMAKE_BUILD_TYPE OR OLD_WITH_DEBUG) + IF(CUSTOM_C_FLAGS) + SET(CMAKE_BUILD_TYPE "" CACHE STRING ${BUILDTYPE_DOCSTRING} FORCE) + ELSE(CMAKE_BUILD_TYPE MATCHES "Debug" OR NOT HAVE_CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING + ${BUILDTYPE_DOCSTRING} FORCE) + ENDIF() + SET(OLD_WITH_DEBUG 0 CACHE INTERNAL "" FORCE) ENDIF() IF(BUILD_CONFIG) diff --git a/config.h.cmake b/config.h.cmake index eb1a5e24ec8..f0473c83af6 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -205,6 +205,7 @@ #cmakedefine HAVE_PTHREAD_KEY_DELETE 1 #cmakedefine HAVE_PTHREAD_KILL 1 #cmakedefine HAVE_PTHREAD_RWLOCK_RDLOCK 1 +#cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP 1 #cmakedefine HAVE_PTHREAD_SETPRIO_NP 1 #cmakedefine HAVE_PTHREAD_SETSCHEDPARAM 1 #cmakedefine HAVE_PTHREAD_SIGMASK 1 diff --git a/configure.cmake b/configure.cmake index 243d3b03b45..31e38aaa2cd 100644 --- a/configure.cmake +++ b/configure.cmake @@ -308,6 +308,7 @@ CHECK_FUNCTION_EXISTS (pthread_condattr_setclock HAVE_PTHREAD_CONDATTR_SETCLOCK) CHECK_FUNCTION_EXISTS (pthread_init HAVE_PTHREAD_INIT) CHECK_FUNCTION_EXISTS (pthread_key_delete HAVE_PTHREAD_KEY_DELETE) CHECK_FUNCTION_EXISTS (pthread_rwlock_rdlock HAVE_PTHREAD_RWLOCK_RDLOCK) +CHECK_FUNCTION_EXISTS (pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK) CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK) CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP) diff --git a/configure.in b/configure.in index f5b3e3da2d2..91e0bd57c0e 100644 --- a/configure.in +++ b/configure.in @@ -2271,7 +2271,8 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bsearch bzero \ locking longjmp lrand48 madvise mallinfo memcpy memmove \ mkstemp mlockall perror poll pread pthread_attr_create mmap mmap64 getpagesize \ pthread_attr_getstacksize pthread_attr_setstacksize pthread_condattr_create \ - pthread_getsequence_np pthread_key_delete pthread_rwlock_rdlock pthread_sigmask \ + pthread_getsequence_np pthread_key_delete pthread_rwlock_rdlock \ + pthread_rwlockattr_setkind_np pthread_sigmask \ readlink realpath rename rint rwlock_init setupterm \ shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \ sighold sigset sigthreadmask port_create sleep thr_yield \ diff --git a/include/my_global.h b/include/my_global.h index dc28682f1f1..b4bc61e0a48 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -83,12 +83,6 @@ #endif #endif /* _WIN32... */ -#ifdef EMBEDDED_LIBRARY -#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE -#undef WITH_PERFSCHEMA_STORAGE_ENGINE -#endif -#endif /* EMBEDDED_LIBRARY */ - #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE #define HAVE_PSI_INTERFACE #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ diff --git a/include/my_pthread.h b/include/my_pthread.h index 0e421f678b0..0b55c70b0fa 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -600,30 +600,76 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp); #define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) #else /* Use our own version of read/write locks */ -typedef struct _my_rw_lock_t { - pthread_mutex_t lock; /* lock for structure */ - pthread_cond_t readers; /* waiting readers */ - pthread_cond_t writers; /* waiting writers */ - int state; /* -1:writer,0:free,>0:readers */ - int waiters; /* number of waiting writers */ -} my_rw_lock_t; - +#define NEED_MY_RW_LOCK 1 #define rw_lock_t my_rw_lock_t +#define my_rwlock_init(A,B) my_rw_init((A), 0) #define rw_rdlock(A) my_rw_rdlock((A)) #define rw_wrlock(A) my_rw_wrlock((A)) #define rw_tryrdlock(A) my_rw_tryrdlock((A)) #define rw_trywrlock(A) my_rw_trywrlock((A)) #define rw_unlock(A) my_rw_unlock((A)) -#define rwlock_destroy(A) my_rwlock_destroy((A)) +#define rwlock_destroy(A) my_rw_destroy((A)) +#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ -extern int my_rwlock_init(my_rw_lock_t *, void *); -extern int my_rwlock_destroy(my_rw_lock_t *); + +/* + Portable read-write locks which prefer readers. + + Required by some algorithms in order to provide correctness. +*/ + +#if defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) +/* + On systems which have a way to specify that readers should + be preferred through attribute mechanism (e.g. Linux) we use + system implementation of read/write locks. +*/ +#define rw_pr_lock_t pthread_rwlock_t +extern int rw_pr_init(rw_pr_lock_t *); +#define rw_pr_rdlock(A) pthread_rwlock_rdlock(A) +#define rw_pr_wrlock(A) pthread_rwlock_wrlock(A) +#define rw_pr_tryrdlock(A) pthread_rwlock_tryrdlock(A) +#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) +#else +/* Otherwise we have to use our own implementation of read/write locks. */ +#define NEED_MY_RW_LOCK 1 +struct st_my_rw_lock_t; +#define rw_pr_lock_t my_rw_lock_t +extern int rw_pr_init(struct st_my_rw_lock_t *); +#define rw_pr_rdlock(A) my_rw_rdlock((A)) +#define rw_pr_wrlock(A) my_rw_wrlock((A)) +#define rw_pr_tryrdlock(A) my_rw_tryrdlock((A)) +#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)) +#endif /* defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) */ + + +#ifdef NEED_MY_RW_LOCK +/* + On systems which don't support native read/write locks, or don't support + read/write locks which prefer readers we have to use own implementation. +*/ +typedef struct st_my_rw_lock_t { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ + my_bool prefer_readers; +} my_rw_lock_t; + +extern int my_rw_init(my_rw_lock_t *, my_bool *); +extern int my_rw_destroy(my_rw_lock_t *); extern int my_rw_rdlock(my_rw_lock_t *); 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 *); -#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ +#endif /* NEED_MY_RW_LOCK */ + #define GETHOSTBYADDR_BUFF_SIZE 2048 diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index 2de514f27bb..0031cb68647 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -1704,3 +1704,56 @@ unlock tables; --echo # already released by commit. handler t1 close; drop tables t1, t2; + + +--echo # +--echo # Bug#51355 handler stmt cause assertion in +--echo # bool MDL_context::try_acquire_lock(MDL_request*) +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +connect(con51355, localhost, root); + +--echo # Connection default +connection default; +CREATE TABLE t1(id INT, KEY id(id)); +HANDLER t1 OPEN; + +--echo # Connection con51355 +connection con51355; +--echo # Sending: +--send DROP TABLE t1 + +--echo # Connection default +connection default; +--echo # This I_S query will cause the handler table to be closed and +--echo # the metadata lock to be released. This will allow DROP TABLE +--echo # to proceed. Waiting for the table to be removed. +let $wait_condition= + SELECT COUNT(*) = 0 FROM information_schema.tables WHERE table_name = "t1"; +--source include/wait_condition.inc + +--echo # Connection con51355 +connection con51355; +--echo # Reaping: DROP TABLE t1 +--reap + +--echo # Connection default +connection default; +--error ER_NO_SUCH_TABLE +HANDLER t1 READ id NEXT; +# This caused an assertion +--error ER_NO_SUCH_TABLE +HANDLER t1 READ id NEXT; + +HANDLER t1 CLOSE; +--echo # Connection con51355 +connection con51355; +disconnect con51355; +--source include/wait_until_disconnected.inc +--echo # Connection default +connection default; + diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index 2136bcd92f1..fd23bfa0562 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -111,3 +111,99 @@ commit; # which was already released by commit. unlock tables; drop tables t1, t2; +# +# Tests for WL#5000 FLUSH TABLES|TABLE table_list WITH READ LOCK +# +# I. Check the incompatible changes in the grammar. +# +flush tables with read lock, hosts; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' hosts' at line 1 +flush privileges, tables; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tables' at line 1 +flush privileges, tables with read lock; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tables with read lock' at line 1 +flush privileges, tables; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tables' at line 1 +flush tables with read lock, tables; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' tables' at line 1 +show tables; +Tables_in_test +# +# II. Check the allowed syntax. +# +drop table if exists t1, t2, t3; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +lock table t1 read, t2 read; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables; +flush tables with read lock; +flush tables t1, t2 with read lock; +flush tables t1, t2 with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +select * from t1; +a +select * from t2; +a +select * from t3; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +insert into t1 (a) values (1); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +insert into t2 (a) values (1); +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +insert into t3 (a) values (1); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +lock table no_such_table read; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +# +# We implicitly left the locked tables +# mode but still have the read lock. +# +insert into t2 (a) values (1); +ERROR HY000: Can't execute the query because you have a conflicting read lock +unlock tables; +insert into t1 (a) values (1); +insert into t2 (a) values (1); +flush table t1, t2 with read lock; +select * from t1; +a +1 +select * from t2; +a +1 +select * from t3; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +insert into t1 (a) values (2); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +insert into t2 (a) values (2); +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +insert into t3 (a) values (2); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +lock table no_such_table read; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +insert into t3 (a) values (2); +# +# III. Concurrent tests. +# +# --> connection default +# +# Check that flush tables <list> with read lock +# does not affect non-locked tables. +# +flush tables t1 with read lock; +# --> connection con1; +select * from t1; +a +1 +select * from t2; +a +1 +insert into t2 (a) values (3); +# --> connection default; +unlock tables; +# --> connection con1 +drop table t1, t2, t3; diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result index c0012c297d1..be4b06396a8 100644 --- a/mysql-test/r/greedy_optimizer.result +++ b/mysql-test/r/greedy_optimizer.result @@ -115,6 +115,8 @@ select @@optimizer_prune_level; @@optimizer_prune_level 1 set optimizer_search_depth=63; +Warnings: +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead select @@optimizer_search_depth; @@optimizer_search_depth 63 diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 58083194b83..08d2fc58e8a 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -1685,3 +1685,28 @@ unlock tables; # already released by commit. handler t1 close; drop tables t1, t2; +# +# Bug#51355 handler stmt cause assertion in +# bool MDL_context::try_acquire_lock(MDL_request*) +# +DROP TABLE IF EXISTS t1; +# Connection default +CREATE TABLE t1(id INT, KEY id(id)); +HANDLER t1 OPEN; +# Connection con51355 +# Sending: +DROP TABLE t1; +# Connection default +# This I_S query will cause the handler table to be closed and +# the metadata lock to be released. This will allow DROP TABLE +# to proceed. Waiting for the table to be removed. +# Connection con51355 +# Reaping: DROP TABLE t1 +# Connection default +HANDLER t1 READ id NEXT; +ERROR 42S02: Table 'test.t1' doesn't exist +HANDLER t1 READ id NEXT; +ERROR 42S02: Table 'test.t1' doesn't exist +HANDLER t1 CLOSE; +# Connection con51355 +# Connection default diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index dd199e40574..2625222ec1a 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -1682,6 +1682,31 @@ unlock tables; handler t1 close; drop tables t1, t2; # +# Bug#51355 handler stmt cause assertion in +# bool MDL_context::try_acquire_lock(MDL_request*) +# +DROP TABLE IF EXISTS t1; +# Connection default +CREATE TABLE t1(id INT, KEY id(id)); +HANDLER t1 OPEN; +# Connection con51355 +# Sending: +DROP TABLE t1; +# Connection default +# This I_S query will cause the handler table to be closed and +# the metadata lock to be released. This will allow DROP TABLE +# to proceed. Waiting for the table to be removed. +# Connection con51355 +# Reaping: DROP TABLE t1 +# Connection default +HANDLER t1 READ id NEXT; +ERROR 42S02: Table 'test.t1' doesn't exist +HANDLER t1 READ id NEXT; +ERROR 42S02: Table 'test.t1' doesn't exist +HANDLER t1 CLOSE; +# Connection con51355 +# Connection default +# # BUG #46456: HANDLER OPEN + TRUNCATE + DROP (temporary) TABLE, crash # CREATE TABLE t1 AS SELECT 1 AS f1; diff --git a/mysql-test/r/implicit_commit.result b/mysql-test/r/implicit_commit.result index 8c330550a3b..d568d05e7b7 100644 --- a/mysql-test/r/implicit_commit.result +++ b/mysql-test/r/implicit_commit.result @@ -658,6 +658,11 @@ YES # # SQLCOM_RESET # +INSERT INTO db1.trans (a) VALUES (1); +reset query cache; +CALL db1.test_if_commit(); +IMPLICIT COMMIT +YES # # SQLCOM_PURGE # diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index c440dafb228..99e1f54e762 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -462,3 +462,17 @@ ERROR 70100: Query execution was interrupted unlock tables; # Switching to connection 'default' drop table t3; +# +# Test for the bug where upgradable metadata locks was acquired +# even if the table to altered was temporary. +# Bug found while working on the related bug #51240. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id INT); +LOCK TABLE t1 WRITE; +# Connection con1 +CREATE TEMPORARY TABLE t1 (id INT); +ALTER TABLE t1 ADD COLUMN j INT; +# Connection default +UNLOCK TABLES; +DROP TABLE t1; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 7a97ced5c1f..a77f3a75f16 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2605,4 +2605,14 @@ ERROR 42000: FUNCTION test.f1 does not exist execute stmt; ERROR 42000: FUNCTION test.f1 does not exist drop table t4, t3, t2, t1; +# +# Bug#51240 ALTER TABLE of a locked MERGE table fails +# +DROP TABLE IF EXISTS m1, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1); +LOCK TABLE m1 WRITE; +ALTER TABLE m1 ADD INDEX (c1); +UNLOCK TABLES; +DROP TABLE m1, t1; End of 6.0 tests diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index d8992e7ccbb..fd692c17efa 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -397,8 +397,9 @@ The following options may be given as the first argument: relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to 63, the - optimizer will switch to the original find_best - search(used for testing/comparison) + optimizer will switch to the original find_best search. + NOTE: The value 63 and its associated behaviour is + deprecated --optimizer-switch=name optimizer_switch=option=val[,option=val...], where option is one of {index_merge, index_merge_union, diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index a9fc6df71a6..00d3aa7502f 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -397,8 +397,9 @@ The following options may be given as the first argument: relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to 63, the - optimizer will switch to the original find_best - search(used for testing/comparison) + optimizer will switch to the original find_best search. + NOTE: The value 63 and its associated behaviour is + deprecated --optimizer-switch=name optimizer_switch=option=val[,option=val...], where option is one of {index_merge, index_merge_union, diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index eab0c51f974..112a86e0c88 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1721,3 +1721,14 @@ SELECT SQL_CACHE * FROM t1 WHERE a IN ERROR 42S22: Unknown column 'SQL_NO_CACHE' in 'field list' DROP TABLE t1; End of 5.1 tests +# +# Bug#51336 Assert in reload_acl_and_cache during RESET QUERY CACHE +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(id INT); +START TRANSACTION; +SELECT * FROM t1; +id +RESET QUERY CACHE; +COMMIT; +DROP TABLE t1; diff --git a/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result b/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result new file mode 100644 index 00000000000..81de6e228e0 --- /dev/null +++ b/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result @@ -0,0 +1,25 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +set @save_general_log = @@global.general_log; +set @save_log_output = @@global.log_output; +set @save_slave_net_timeout = @@global.slave_net_timeout; +set @@global.general_log = ON; +set @@global.log_output = 'table,file'; +include/stop_slave.inc +set @@global.slave_net_timeout = @@global.net_read_timeout * 2; +change master to master_host = '127.0.0.1',master_port = MASTER_PORT, +master_user = 'root', master_heartbeat_period = 0; +include/start_slave.inc +include/stop_slave.inc +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time desc limit 1 into @ts_last; +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time asc limit 1 into @ts_prev; +select @result as 'Must be 1'; +Must be 1 +1 +set @@global.general_log = @save_general_log; +set @@global.log_output = @save_log_output; +set @@global.slave_net_timeout = @save_slave_net_timeout; diff --git a/mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt new file mode 100644 index 00000000000..281566c9ad9 --- /dev/null +++ b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt @@ -0,0 +1 @@ +--net_read_timeout=5 diff --git a/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test new file mode 100644 index 00000000000..9a2cdc3b596 --- /dev/null +++ b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test @@ -0,0 +1,81 @@ +# +# Testing reconnecting by slave as specified by `slave_net_timeout' +# +# Bug #50296 Slave reconnects earlier than the prescribed slave_net_timeout value +# +--source include/have_csv.inc +--source include/master-slave.inc + + +# save global env +connection master; +set @save_general_log = @@global.general_log; +set @save_log_output = @@global.log_output; + +connection slave; +set @save_slave_net_timeout = @@global.slave_net_timeout; + +connection master; +set @@global.general_log = ON; +set @@global.log_output = 'table,file'; + +connection slave; +--source include/stop_slave.inc +--disable_warnings +set @@global.slave_net_timeout = @@global.net_read_timeout * 2; +--enable_warnings +let $idle_time=`select @@global.slave_net_timeout * 2`; + +# +# if heartbeat is disabled then reconnecting to the idle master +# should happen with `slave_net_timeout' period. +# Since it's the real time that is measured, `slave_net_timeout' +# merely guarantees that reconnecting can *not* happen earlier of a value specified. +# That is there can't an exact estimate for how many time it will happen. +# +# The following lines verify that having idle master +# for more than 2 * slave_net_timeout seconds and +# slave.net_read_timeout < slave_net_timeout +# won't cause reconnecting by the slave within at least +# slave_net_timeout interval. +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host = '127.0.0.1',master_port = $MASTER_MYPORT, +master_user = 'root', master_heartbeat_period = 0; + +let $slave_net_timeout = `select @@global.slave_net_timeout`; + +--source include/start_slave.inc + +--disable_query_log +--disable_result_log +eval select 'master is idle for ', sleep($idle_time); +--enable_result_log +--enable_query_log + +--source include/stop_slave.inc + +# querying general-log + +connection master; + +# In particular the last reconnection timestamp must be greater or equal to +# the previous one + slave_net_timeout + +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time desc limit 1 into @ts_last; +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time asc limit 1 into @ts_prev; + +--disable_query_log +eval select time_to_sec(@ts_last) - $slave_net_timeout >= time_to_sec(@ts_prev) into @result; +--enable_query_log + +select @result as 'Must be 1'; + +# cleanup + +# restore global env +connection master; +set @@global.general_log = @save_general_log; +set @@global.log_output = @save_log_output; +connection slave; +set @@global.slave_net_timeout = @save_slave_net_timeout; + diff --git a/mysql-test/suite/perfschema/r/misc.result b/mysql-test/suite/perfschema/r/misc.result index d944b4b1d3d..3c0a4a58e08 100644 --- a/mysql-test/suite/perfschema/r/misc.result +++ b/mysql-test/suite/perfschema/r/misc.result @@ -11,3 +11,17 @@ create table test.t1 like performance_schema.EVENTS_WAITS_CURRENT; ERROR HY000: Invalid performance_schema usage. create table performance_schema.t1(a int); ERROR 42000: CREATE command denied to user 'root'@'localhost' for table 't1' +drop table if exists test.ghost; +create table test.ghost (a int, b int); +alter table test.ghost add index index_a(a); +alter table test.ghost add index index_b(b); +insert into test.ghost values (1, 3); +insert into test.ghost values (2, 4); +select * from test.ghost; +a b +1 3 +2 4 +drop table test.ghost; +select * from performance_schema.FILE_INSTANCES +where file_name like "%ghost%"; +FILE_NAME EVENT_NAME OPEN_COUNT diff --git a/mysql-test/suite/perfschema/t/misc.test b/mysql-test/suite/perfschema/t/misc.test index d9b97d8441e..749eccca793 100644 --- a/mysql-test/suite/perfschema/t/misc.test +++ b/mysql-test/suite/perfschema/t/misc.test @@ -55,3 +55,24 @@ create table test.t1 like performance_schema.EVENTS_WAITS_CURRENT; --error ER_TABLEACCESS_DENIED_ERROR create table performance_schema.t1(a int); +# +# Bug#51447 performance schema evil twin files +# + +--disable_warnings +drop table if exists test.ghost; +--enable_warnings + +create table test.ghost (a int, b int); +alter table test.ghost add index index_a(a); +alter table test.ghost add index index_b(b); +insert into test.ghost values (1, 3); +insert into test.ghost values (2, 4); +select * from test.ghost; + +drop table test.ghost; + +# Shoud return nothing +select * from performance_schema.FILE_INSTANCES + where file_name like "%ghost%"; + diff --git a/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result b/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result index 4d94fb02be7..de448d3e2fc 100644 --- a/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result +++ b/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result @@ -10,6 +10,7 @@ SELECT @start_session_value; SET @@global.optimizer_search_depth = 100; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '100' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SET @@global.optimizer_search_depth = DEFAULT; SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth @@ -17,6 +18,7 @@ SELECT @@global.optimizer_search_depth; SET @@session.optimizer_search_depth = 200; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '200' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SET @@session.optimizer_search_depth = DEFAULT; SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth @@ -44,6 +46,8 @@ SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 62 SET @@global.optimizer_search_depth = 63; +Warnings: +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 63 @@ -61,6 +65,8 @@ SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 62 SET @@session.optimizer_search_depth = 63; +Warnings: +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 63 @@ -68,6 +74,7 @@ SELECT @@session.optimizer_search_depth; SET @@global.optimizer_search_depth = 64; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '64' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 63 @@ -80,6 +87,7 @@ SELECT @@global.optimizer_search_depth; SET @@global.optimizer_search_depth = 65536; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '65536' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 63 @@ -96,6 +104,7 @@ SELECT @@global.optimizer_search_depth; SET @@session.optimizer_search_depth = 64; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '64' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 63 @@ -110,6 +119,7 @@ ERROR 42000: Incorrect argument type to variable 'optimizer_search_depth' SET @@session.optimizer_search_depth = 65550; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '65550' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 63 diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index d41ac3100b0..582d2562fc6 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -224,3 +224,103 @@ commit; --echo # which was already released by commit. unlock tables; drop tables t1, t2; + + + +--echo # +--echo # Tests for WL#5000 FLUSH TABLES|TABLE table_list WITH READ LOCK +--echo # +--echo # I. Check the incompatible changes in the grammar. +--echo # +--error ER_PARSE_ERROR +flush tables with read lock, hosts; +--error ER_PARSE_ERROR +flush privileges, tables; +--error ER_PARSE_ERROR +flush privileges, tables with read lock; +--error ER_PARSE_ERROR +flush privileges, tables; +--error ER_PARSE_ERROR +flush tables with read lock, tables; +show tables; +--echo # +--echo # II. Check the allowed syntax. +--echo # +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +lock table t1 read, t2 read; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +unlock tables; +flush tables with read lock; +flush tables t1, t2 with read lock; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables t1, t2 with read lock; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +select * from t1; +select * from t2; +--error ER_TABLE_NOT_LOCKED +select * from t3; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t1 (a) values (1); +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t2 (a) values (1); +--error ER_TABLE_NOT_LOCKED +insert into t3 (a) values (1); +--error ER_NO_SUCH_TABLE +lock table no_such_table read; +--echo # +--echo # We implicitly left the locked tables +--echo # mode but still have the read lock. +--echo # +--error ER_CANT_UPDATE_WITH_READLOCK +insert into t2 (a) values (1); +unlock tables; +insert into t1 (a) values (1); +insert into t2 (a) values (1); +flush table t1, t2 with read lock; +select * from t1; +select * from t2; +--error ER_TABLE_NOT_LOCKED +select * from t3; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t1 (a) values (2); +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t2 (a) values (2); +--error ER_TABLE_NOT_LOCKED +insert into t3 (a) values (2); +--error ER_NO_SUCH_TABLE +lock table no_such_table read; +insert into t3 (a) values (2); + + +--echo # +--echo # III. Concurrent tests. +--echo # +connect (con1,localhost,root,,); +--echo # --> connection default +--echo # +--echo # Check that flush tables <list> with read lock +--echo # does not affect non-locked tables. +connection default; +--echo # +flush tables t1 with read lock; +--echo # --> connection con1; +connection con1; +select * from t1; +select * from t2; +insert into t2 (a) values (3); +--echo # --> connection default; +connection default; +unlock tables; +--echo # --> connection con1 +connection con1; +disconnect con1; +--source include/wait_until_disconnected.inc +connection default; +drop table t1, t2, t3; diff --git a/mysql-test/t/implicit_commit.test b/mysql-test/t/implicit_commit.test index d8ffd6e9452..b10788bd891 100644 --- a/mysql-test/t/implicit_commit.test +++ b/mysql-test/t/implicit_commit.test @@ -697,6 +697,10 @@ source include/implicit_commit_helper.inc; --echo # SQLCOM_RESET --echo # +let $statement= + reset query cache; +source include/implicit_commit_helper.inc; + --echo # --echo # SQLCOM_PURGE --echo # diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index c34dcb05dd4..6983947d1c4 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -1092,5 +1092,31 @@ disconnect con2; drop table t3; +--echo # +--echo # Test for the bug where upgradable metadata locks was acquired +--echo # even if the table to altered was temporary. +--echo # Bug found while working on the related bug #51240. +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (id INT); +LOCK TABLE t1 WRITE; + +--echo # Connection con1 +connect (con1, localhost, root); +CREATE TEMPORARY TABLE t1 (id INT); +# This alter should not block and timeout. +ALTER TABLE t1 ADD COLUMN j INT; + +--echo # Connection default +connection default; +disconnect con1; +UNLOCK TABLES; +DROP TABLE t1; + + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index f0d8960322e..4035752b72d 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -2089,5 +2089,24 @@ execute stmt; execute stmt; drop table t4, t3, t2, t1; + +--echo # +--echo # Bug#51240 ALTER TABLE of a locked MERGE table fails +--echo # + +--disable_warnings +DROP TABLE IF EXISTS m1, t1; +--enable_warnings + +CREATE TABLE t1 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1); +LOCK TABLE m1 WRITE; +# This used to cause an error. +ALTER TABLE m1 ADD INDEX (c1); + +UNLOCK TABLES; +DROP TABLE m1, t1; + + --echo End of 6.0 tests diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 993f231759b..ce49ca89eca 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1363,3 +1363,22 @@ SELECT SQL_CACHE * FROM t1 WHERE a IN DROP TABLE t1; --echo End of 5.1 tests + + +--echo # +--echo # Bug#51336 Assert in reload_acl_and_cache during RESET QUERY CACHE +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(id INT); + +START TRANSACTION; +SELECT * FROM t1; +# This caused an assert +RESET QUERY CACHE; + +COMMIT; +DROP TABLE t1; diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c index 0aa4d3fc3c4..2ac4a00695e 100644 --- a/mysys/thr_rwlock.c +++ b/mysys/thr_rwlock.c @@ -16,7 +16,8 @@ /* Synchronization - readers / writer thread locks */ #include "mysys_priv.h" -#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT) +#if defined(THREAD) +#if defined(NEED_MY_RW_LOCK) #include <errno.h> /* @@ -58,7 +59,7 @@ * Mountain View, California 94043 */ -int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused))) +int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr) { pthread_condattr_t cond_attr; @@ -70,12 +71,14 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused))) rwp->state = 0; rwp->waiters = 0; + /* If attribute argument is NULL use default value - prefer writers. */ + rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE; return(0); } -int my_rwlock_destroy(rw_lock_t *rwp) +int my_rw_destroy(my_rw_lock_t *rwp) { pthread_mutex_destroy( &rwp->lock ); pthread_cond_destroy( &rwp->readers ); @@ -84,12 +87,13 @@ int my_rwlock_destroy(rw_lock_t *rwp) } -int my_rw_rdlock(rw_lock_t *rwp) +int my_rw_rdlock(my_rw_lock_t *rwp) { pthread_mutex_lock(&rwp->lock); /* active or queued writers */ - while (( rwp->state < 0 ) || rwp->waiters) + while (( rwp->state < 0 ) || + (rwp->waiters && ! rwp->prefer_readers)) pthread_cond_wait( &rwp->readers, &rwp->lock); rwp->state++; @@ -97,11 +101,12 @@ int my_rw_rdlock(rw_lock_t *rwp) return(0); } -int my_rw_tryrdlock(rw_lock_t *rwp) +int my_rw_tryrdlock(my_rw_lock_t *rwp) { int res; pthread_mutex_lock(&rwp->lock); - if ((rwp->state < 0 ) || rwp->waiters) + if ((rwp->state < 0 ) || + (rwp->waiters && ! rwp->prefer_readers)) res= EBUSY; /* Can't get lock */ else { @@ -113,7 +118,7 @@ int my_rw_tryrdlock(rw_lock_t *rwp) } -int my_rw_wrlock(rw_lock_t *rwp) +int my_rw_wrlock(my_rw_lock_t *rwp) { pthread_mutex_lock(&rwp->lock); rwp->waiters++; /* another writer queued */ @@ -127,7 +132,7 @@ int my_rw_wrlock(rw_lock_t *rwp) } -int my_rw_trywrlock(rw_lock_t *rwp) +int my_rw_trywrlock(my_rw_lock_t *rwp) { int res; pthread_mutex_lock(&rwp->lock); @@ -143,7 +148,7 @@ int my_rw_trywrlock(rw_lock_t *rwp) } -int my_rw_unlock(rw_lock_t *rwp) +int my_rw_unlock(my_rw_lock_t *rwp) { DBUG_PRINT("rw_unlock", ("state: %d waiters: %d", rwp->state, rwp->waiters)); @@ -160,7 +165,8 @@ int my_rw_unlock(rw_lock_t *rwp) } else { - if ( --rwp->state == 0 ) /* no more readers */ + if ( --rwp->state == 0 && /* no more readers */ + rwp->waiters) pthread_cond_signal( &rwp->writers ); } @@ -168,4 +174,30 @@ int my_rw_unlock(rw_lock_t *rwp) return(0); } -#endif + +int rw_pr_init(struct st_my_rw_lock_t *rwlock) +{ + my_bool prefer_readers_attr= TRUE; + return my_rw_init(rwlock, &prefer_readers_attr); +} + +#else + +/* + We are on system which has native read/write locks which support + preferring of readers. +*/ + +int rw_pr_init(rw_pr_lock_t *rwlock) +{ + pthread_rwlockattr_t rwlock_attr; + + pthread_rwlockattr_init(&rwlock_attr); + pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_READER_NP); + pthread_rwlock_init(rwlock, NULL); + pthread_rwlockattr_destroy(&rwlock_attr); + return 0; +} + +#endif /* defined(NEED_MY_RW_LOCK) */ +#endif /* defined(THREAD) */ diff --git a/plugin/semisync/CMakeLists.txt b/plugin/semisync/CMakeLists.txt index 0d48ad55382..2ebd67292f3 100644 --- a/plugin/semisync/CMakeLists.txt +++ b/plugin/semisync/CMakeLists.txt @@ -11,7 +11,7 @@ # # 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 02 +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 92cba86fc8a..f838d27a241 100755 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -103,9 +103,9 @@ ENDIF() IF(NOT FIND_PROC) # BSD style EXECUTE_PROCESS(COMMAND ps -uaxww OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) - IF(result MATCHES 0) + IF(result MATCHES 0) SET( FIND_PROC - "ps -uaxww | grep -v \" grep\" | grep -v mysqld_safe | grep -- "\$MYSQLD\" | grep \" $PID \" > /dev/null") + "ps -uaxww | grep -v \" grep\" | grep -v mysqld_safe | grep -- \"$MYSQLD\" | grep \" $PID \" > /dev/null") ENDIF() ENDIF() @@ -113,20 +113,15 @@ IF(NOT FIND_PROC) # SysV style EXECUTE_PROCESS(COMMAND ps -ef OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) IF(result MATCHES 0) - SET( FIND_PROC "ps -ef | grep -v \" grep\" | grep -v mysqld_safe | grep -- "\$MYSQLD\" | grep \" $PID \" > /dev/null") + SET( FIND_PROC "ps -ef | grep -v \" grep\" | grep -v mysqld_safe | grep -- \"$MYSQLD\" | grep \" $PID \" > /dev/null") ENDIF() ENDIF() -EXECUTE_PROCESS(COMMAND sh -c "kill -0 $$" OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result2) -IF(result3 MATCHES 0) +EXECUTE_PROCESS(COMMAND sh -c "kill -0 $$" OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) +IF(result MATCHES 0) SET(CHECK_PID "kill -0 $PID > /dev/null 2> /dev/null") ELSE() - EXECUTE_PROCESS(COMMAND sh -c "kill -s 0 $$" OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result3) - IF(result4 MATCHES 0) - SET(CHECK_PID "kill -s 0 $PID > /dev/null 2> /dev/null") - ELSE() - SET(CHECK_PID "kill -s SIGCONT $PID > /dev/null 2> /dev/null") - ENDIF() + SET(CHECK_PID "kill -s SIGCONT $PID > /dev/null 2> /dev/null") ENDIF() ENDIF(UNIX) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 21fca0c0848..90f759739d0 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -56,6 +56,8 @@ Usage: $0 db_name[./table_regex/] [new_db_name | directory] -h, --host=# hostname for local server when connecting over TCP/IP -P, --port=# port to use when connecting to local server with TCP/IP -S, --socket=# socket to use when connecting to local server + --old_server connect to old MySQL-server (before v5.5) which + doesn't have FLUSH TABLES WITH READ LOCK fully implemented. --allowold don\'t abort if target dir already exists (rename it _old) --addtodest don\'t rename target dir if it exists, just add files to it @@ -103,6 +105,7 @@ GetOptions( \%opt, "password|p=s", "port|P=s", "socket|S=s", + "old_server", "allowold!", "keepold!", "addtodest!", @@ -441,21 +444,37 @@ if ( $opt{checkpoint} || $opt{record_log_pos} ) { my $hc_started = time; # count from time lock is granted if ( $opt{dryrun} ) { - print "LOCK TABLES $hc_locks\n"; - print "FLUSH TABLES /*!32323 $hc_tables */\n"; + if ( $opt{old_server} ) { + print "LOCK TABLES $hc_locks\n"; + print "FLUSH TABLES /*!32323 $hc_tables */\n"; + } + else { + print "FLUSH TABLES $hc_tables WITH READ LOCK\n"; + } + print "FLUSH LOGS\n" if ( $opt{flushlog} ); print "RESET MASTER\n" if ( $opt{resetmaster} ); print "RESET SLAVE\n" if ( $opt{resetslave} ); } else { my $start = time; - $dbh->do("LOCK TABLES $hc_locks"); - printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; - $hc_started = time; # count from time lock is granted + if ( $opt{old_server} ) { + $dbh->do("LOCK TABLES $hc_locks"); + printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; + $hc_started = time; # count from time lock is granted + + # flush tables to make on-disk copy up to date + $start = time; + $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + } + else { + $dbh->do("FLUSH TABLES $hc_tables WITH READ LOCK"); + printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; + $hc_started = time; # count from time lock is granted - # flush tables to make on-disk copy up to date - $start = time; - $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + # flush tables to make on-disk copy up to date + $start = time; + } printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} ); $dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} ); @@ -975,6 +994,10 @@ when using the --host option. UNIX domain socket to use when connecting to local server. +=item --old_server + +Use old server (pre v5.5) commands. + =item --noindices Don\'t include index files in copy. Only up to the first 2048 bytes diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index e9bcecc459d..0696652deb1 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -574,7 +574,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, tables.init_one_table("mysql", 5, "event", 5, "event", lock_type); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { close_thread_tables(thd); DBUG_RETURN(TRUE); @@ -1129,11 +1129,10 @@ Event_db_repository::check_system_tables(THD *thd) DBUG_ENTER("Event_db_repository::check_system_tables"); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); - /* Check mysql.db */ tables.init_one_table("mysql", 5, "db", 2, "db", TL_READ); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { ret= 1; sql_print_error("Cannot open mysql.db"); @@ -1148,7 +1147,7 @@ Event_db_repository::check_system_tables(THD *thd) /* Check mysql.user */ tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { ret= 1; sql_print_error("Cannot open mysql.user"); @@ -1168,7 +1167,7 @@ Event_db_repository::check_system_tables(THD *thd) /* Check mysql.event */ tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { ret= 1; sql_print_error("Cannot open mysql.event"); diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 733f2a7167f..3ceb1597a41 100755 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -203,6 +203,9 @@ pre_init_event_thread(THD* thd) thd->version= refresh_version; thd->set_time(); + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; + DBUG_VOID_RETURN; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b0276e14ebf..05a42220caf 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -9504,6 +9504,8 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) my_net_init(&thd->net, 0); thd->main_security_ctx.master_access= ~0; thd->main_security_ctx.priv_user = 0; + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; CHARSET_INFO *charset_connection; charset_connection= get_charset_by_csname("utf8", diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index ed2bdfbbe71..279d5b4c242 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -2348,7 +2348,7 @@ static int open_ndb_binlog_index(THD *thd, TABLE **ndb_binlog_index) tables->required_type= FRMTYPE_TABLE; uint counter; thd->clear_error(); - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, 0)) { if (thd->killed) sql_print_error("NDB Binlog: Opening ndb_binlog_index: killed"); @@ -3675,6 +3675,8 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) my_net_init(&thd->net, 0); thd->main_security_ctx.master_access= ~0; thd->main_security_ctx.priv_user= 0; + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; /* Set up ndb binlog diff --git a/sql/lock.cc b/sql/lock.cc index fa58e43f6bb..3ff131bb828 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -251,6 +251,7 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock) MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables. + MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value. @param need_reopen Out parameter, TRUE if some tables were altered or deleted and should be reopened by caller. @@ -277,6 +278,9 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, if (mysql_lock_tables_check(thd, tables, count, flags)) DBUG_RETURN (NULL); + ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? + LONG_TIMEOUT : thd->variables.lock_wait_timeout; + for (;;) { if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS, @@ -336,8 +340,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + sql_lock->lock_count, sql_lock->lock_count, - thd->lock_id, - thd->variables.lock_wait_timeout)]; + thd->lock_id, timeout)]; if (rc > 1) /* a timeout or a deadlock */ { if (sql_lock->table_count) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5d20ff91442..6412f0047d1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2521,6 +2521,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, case SQLCOM_ASSIGN_TO_KEYCACHE: case SQLCOM_PRELOAD_KEYS: case SQLCOM_FLUSH: + case SQLCOM_RESET: case SQLCOM_CHECK: implicit_commit= TRUE; break; @@ -7492,7 +7493,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* A small test to verify that objects have consistent types */ DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); - if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0)) { uint actual_error= thd->stmt_da->sql_errno(); if (thd->is_slave_error || thd->is_fatal_error) diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index dd25ba0b085..9b46ad83b14 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -73,7 +73,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ thd->lex->set_stmt_row_injection(); - if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0)) { uint actual_error= thd->stmt_da->sql_errno(); if (thd->is_slave_error || thd->is_fatal_error) diff --git a/sql/mdl.cc b/sql/mdl.cc index 28cff420e0d..f9a4e10aade 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -148,10 +148,37 @@ public: /** Read-write lock protecting this lock context. - TODO/FIXME: Replace with RW-lock which will prefer readers - on all platforms and not only on Linux. + @note The fact that we use read-write lock prefers readers here is + important as deadlock detector won't work correctly otherwise. + + For example, imagine that we have following waiters graph: + + ctxA -> obj1 -> ctxB -> obj1 -| + ^ | + |----------------------------| + + and both ctxA and ctxB start deadlock detection process: + + ctxA read-locks obj1 ctxB read-locks obj2 + ctxA goes deeper ctxB goes deeper + + Now ctxC comes in who wants to start waiting on obj1, also + ctxD comes in who wants to start waiting on obj2. + + ctxC tries to write-lock obj1 ctxD tries to write-lock obj2 + ctxC is blocked ctxD is blocked + + Now ctxA and ctxB resume their search: + + ctxA tries to read-lock obj2 ctxB tries to read-lock obj1 + + If m_rwlock prefers writes (or fair) both ctxA and ctxB would be + blocked because of pending write locks from ctxD and ctxC + correspondingly. Thus we will get a deadlock in deadlock detector. + If m_wrlock prefers readers (actually ignoring pending writers is + enough) ctxA and ctxB will continue and no deadlock will occur. */ - rw_lock_t m_rwlock; + rw_pr_lock_t m_rwlock; bool is_empty() const { @@ -213,12 +240,12 @@ public: m_ref_release(0), m_is_destroyed(FALSE) { - my_rwlock_init(&m_rwlock, NULL); + rw_pr_init(&m_rwlock); } virtual ~MDL_lock() { - rwlock_destroy(&m_rwlock); + rw_pr_destroy(&m_rwlock); } inline static void destroy(MDL_lock *lock); public: @@ -480,7 +507,7 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) lock->m_ref_usage++; mysql_mutex_unlock(&m_mutex); - rw_wrlock(&lock->m_rwlock); + rw_pr_wrlock(&lock->m_rwlock); lock->m_ref_release++; if (unlikely(lock->m_is_destroyed)) { @@ -495,7 +522,7 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) */ uint ref_usage= lock->m_ref_usage; uint ref_release= lock->m_ref_release; - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); if (ref_usage == ref_release) MDL_lock::destroy(lock); return TRUE; @@ -538,7 +565,7 @@ void MDL_map::remove(MDL_lock *lock) lock->m_is_destroyed= TRUE; ref_usage= lock->m_ref_usage; ref_release= lock->m_ref_release; - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); mysql_mutex_unlock(&m_mutex); if (ref_usage == ref_release) MDL_lock::destroy(lock); @@ -559,7 +586,7 @@ MDL_context::MDL_context() m_deadlock_weight(0), m_signal(NO_WAKE_UP) { - my_rwlock_init(&m_waiting_for_lock, NULL); + rw_pr_init(&m_waiting_for_lock); mysql_mutex_init(NULL /* pfs key */, &m_signal_lock, NULL); mysql_cond_init(NULL /* pfs key */, &m_signal_cond, NULL); } @@ -581,7 +608,7 @@ void MDL_context::destroy() { DBUG_ASSERT(m_tickets.is_empty()); - rwlock_destroy(&m_waiting_for_lock); + rw_pr_destroy(&m_waiting_for_lock); mysql_mutex_destroy(&m_signal_lock); mysql_cond_destroy(&m_signal_cond); } @@ -1071,7 +1098,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, void MDL_lock::remove_ticket(Ticket_list MDL_lock::*list, MDL_ticket *ticket) { - rw_wrlock(&m_rwlock); + rw_pr_wrlock(&m_rwlock); (this->*list).remove_ticket(ticket); if (is_empty()) mdl_locks.remove(this); @@ -1082,7 +1109,7 @@ void MDL_lock::remove_ticket(Ticket_list MDL_lock::*list, MDL_ticket *ticket) which now might be able to do it. Wake them up! */ wake_up_waiters(); - rw_unlock(&m_rwlock); + rw_pr_unlock(&m_rwlock); } } @@ -1102,9 +1129,9 @@ bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type) mysql_mutex_assert_not_owner(&LOCK_open); - rw_rdlock(&m_rwlock); + rw_pr_rdlock(&m_rwlock); result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]); - rw_unlock(&m_rwlock); + rw_pr_unlock(&m_rwlock); return result; } @@ -1298,7 +1325,7 @@ MDL_context::try_acquire_lock(MDL_request *mdl_request) { ticket->m_lock= lock; lock->m_granted.add_ticket(ticket); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); m_tickets.push_front(ticket); @@ -1308,7 +1335,7 @@ MDL_context::try_acquire_lock(MDL_request *mdl_request) { /* We can't get here if we allocated a new lock. */ DBUG_ASSERT(! lock->is_empty()); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); MDL_ticket::destroy(ticket); } @@ -1349,9 +1376,9 @@ MDL_context::clone_ticket(MDL_request *mdl_request) ticket->m_lock= mdl_request->ticket->m_lock; mdl_request->ticket= ticket; - rw_wrlock(&ticket->m_lock->m_rwlock); + rw_pr_wrlock(&ticket->m_lock->m_rwlock); ticket->m_lock->m_granted.add_ticket(ticket); - rw_unlock(&ticket->m_lock->m_rwlock); + rw_pr_unlock(&ticket->m_lock->m_rwlock); m_tickets.push_front(ticket); @@ -1457,7 +1484,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request, if (ticket->is_upgradable_or_exclusive()) lock->notify_shared_locks(this); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); set_deadlock_weight(mdl_request->get_deadlock_weight()); will_wait_for(ticket); @@ -1492,7 +1519,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request, my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); return TRUE; } - rw_wrlock(&lock->m_rwlock); + rw_pr_wrlock(&lock->m_rwlock); } lock->m_waiting.remove_ticket(ticket); @@ -1502,7 +1529,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request, (*lock->cached_object_release_hook)(lock->cached_object); lock->cached_object= NULL; - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); m_tickets.push_front(ticket); @@ -1647,7 +1674,7 @@ MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket, is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket); /* Merge the acquired and the original lock. @todo: move to a method. */ - rw_wrlock(&mdl_ticket->m_lock->m_rwlock); + rw_pr_wrlock(&mdl_ticket->m_lock->m_rwlock); if (is_new_ticket) mdl_ticket->m_lock->m_granted.remove_ticket(mdl_xlock_request.ticket); /* @@ -1659,7 +1686,7 @@ MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket, mdl_ticket->m_type= MDL_EXCLUSIVE; mdl_ticket->m_lock->m_granted.add_ticket(mdl_ticket); - rw_unlock(&mdl_ticket->m_lock->m_rwlock); + rw_pr_unlock(&mdl_ticket->m_lock->m_rwlock); if (is_new_ticket) { @@ -1677,7 +1704,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket, MDL_ticket *ticket; bool result= FALSE; - rw_rdlock(&m_rwlock); + rw_pr_rdlock(&m_rwlock); Ticket_iterator granted_it(m_granted); Ticket_iterator waiting_it(m_waiting); @@ -1729,7 +1756,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket, } end: - rw_unlock(&m_rwlock); + rw_pr_unlock(&m_rwlock); return result; } @@ -1738,7 +1765,7 @@ bool MDL_context::find_deadlock(Deadlock_detection_context *deadlock_ctx) { bool result= FALSE; - rw_rdlock(&m_waiting_for_lock); + rw_pr_rdlock(&m_waiting_for_lock); if (m_waiting_for) { @@ -1767,14 +1794,14 @@ bool MDL_context::find_deadlock(Deadlock_detection_context *deadlock_ctx) deadlock_ctx->victim= this; else if (deadlock_ctx->victim->m_deadlock_weight >= m_deadlock_weight) { - rw_unlock(&deadlock_ctx->victim->m_waiting_for_lock); + rw_pr_unlock(&deadlock_ctx->victim->m_waiting_for_lock); deadlock_ctx->victim= this; } else - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); } else - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); return result; } @@ -1800,7 +1827,7 @@ bool MDL_context::find_deadlock() if (deadlock_ctx.victim != this) { deadlock_ctx.victim->awake(VICTIM_WAKE_UP); - rw_unlock(&deadlock_ctx.victim->m_waiting_for_lock); + rw_pr_unlock(&deadlock_ctx.victim->m_waiting_for_lock); /* After adding new arc to waiting graph we found that it participates in some loop (i.e. there is a deadlock). We decided to destroy this @@ -1813,7 +1840,7 @@ bool MDL_context::find_deadlock() else { DBUG_ASSERT(&deadlock_ctx.victim->m_waiting_for_lock == &m_waiting_for_lock); - rw_unlock(&deadlock_ctx.victim->m_waiting_for_lock); + rw_pr_unlock(&deadlock_ctx.victim->m_waiting_for_lock); return TRUE; } } @@ -1870,14 +1897,14 @@ MDL_context::wait_for_lock(MDL_request *mdl_request, ulong lock_wait_timeout) if (lock->can_grant_lock(mdl_request->type, this)) { - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); return FALSE; } MDL_ticket *pending_ticket; if (! (pending_ticket= MDL_ticket::create(this, mdl_request->type))) { - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); return TRUE; } @@ -1886,7 +1913,7 @@ MDL_context::wait_for_lock(MDL_request *mdl_request, ulong lock_wait_timeout) lock->m_waiting.add_ticket(pending_ticket); wait_reset(); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); set_deadlock_weight(MDL_DEADLOCK_WEIGHT_DML); will_wait_for(pending_ticket); @@ -2037,7 +2064,7 @@ void MDL_ticket::downgrade_exclusive_lock(enum_mdl_type type) if (m_type != MDL_EXCLUSIVE) return; - rw_wrlock(&m_lock->m_rwlock); + rw_pr_wrlock(&m_lock->m_rwlock); /* To update state of MDL_lock object correctly we need to temporarily exclude ticket from the granted queue and then include it back. @@ -2046,7 +2073,7 @@ void MDL_ticket::downgrade_exclusive_lock(enum_mdl_type type) m_type= type; m_lock->m_granted.add_ticket(this); m_lock->wake_up_waiters(); - rw_unlock(&m_lock->m_rwlock); + rw_pr_unlock(&m_lock->m_rwlock); } diff --git a/sql/mdl.h b/sql/mdl.h index 59bc1f64762..42461f6ac2f 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -624,10 +624,11 @@ private: /** Read-write lock protecting m_waiting_for member. - TODO/FIXME: Replace with RW-lock which will prefer readers - on all platforms and not only on Linux. + @note The fact that this read-write lock prefers readers is + important as deadlock detector won't work correctly + otherwise. @sa Comment for MDL_lock::m_rwlock. */ - rw_lock_t m_waiting_for_lock; + rw_pr_lock_t m_waiting_for_lock; MDL_ticket *m_waiting_for; uint m_deadlock_weight; /** @@ -651,9 +652,9 @@ private: void will_wait_for(MDL_ticket *pending_ticket) { - rw_wrlock(&m_waiting_for_lock); + rw_pr_wrlock(&m_waiting_for_lock); m_waiting_for= pending_ticket; - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); } void set_deadlock_weight(uint weight) @@ -669,9 +670,9 @@ private: void stop_waiting() { - rw_wrlock(&m_waiting_for_lock); + rw_pr_wrlock(&m_waiting_for_lock); m_waiting_for= NULL; - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); } void wait_reset() diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9cf7f72015d..3f2b9cf3093 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1575,26 +1575,16 @@ open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags) return open_tables(thd, tables, counter, flags, &prelocking_strategy); } /* open_and_lock_tables with optional derived handling */ -bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, - bool derived, uint flags, - Prelocking_strategy *prelocking_strategy); -inline bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, - bool derived, uint flags) +bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, + bool derived, uint flags, + Prelocking_strategy *prelocking_strategy); +inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, + bool derived, uint flags) { DML_prelocking_strategy prelocking_strategy; - return open_and_lock_tables_derived(thd, tables, derived, flags, - &prelocking_strategy); -} -/* simple open_and_lock_tables without derived handling */ -inline bool simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) -{ - return open_and_lock_tables_derived(thd, tables, FALSE, 0); -} -/* open_and_lock_tables with derived handling */ -inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) -{ - return open_and_lock_tables_derived(thd, tables, TRUE, 0); + return open_and_lock_tables(thd, tables, derived, flags, + &prelocking_strategy); } /* simple open_and_lock_tables without derived handling for single table */ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, @@ -1988,7 +1978,8 @@ extern ulong slow_launch_threads, slow_launch_time; extern ulong table_cache_size, table_def_size; extern MYSQL_PLUGIN_IMPORT ulong max_connections; extern ulong max_connect_errors, connect_timeout; -extern ulong slave_net_timeout, slave_trans_retries; +extern ulong slave_trans_retries; +extern uint slave_net_timeout; extern ulong what_to_log,flush_time; extern ulong query_buff_size; extern ulong max_prepared_stmt_count, prepared_stmt_count; @@ -2184,11 +2175,17 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, in parser. */ #define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0800 +/** + 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 0x1000 /** Please refer to the internals manual. */ #define MYSQL_OPEN_REOPEN (MYSQL_LOCK_IGNORE_FLUSH |\ MYSQL_LOCK_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) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 133bec99cda..3799562968e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -464,7 +464,8 @@ ulong table_cache_size, table_def_size; ulong what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; -ulong slave_net_timeout, slave_trans_retries; +ulong slave_trans_retries; +uint slave_net_timeout; uint slave_exec_mode_options; ulonglong slave_type_conversions_options; ulong thread_cache_size=0, thread_pool_size= 0; diff --git a/sql/slave.cc b/sql/slave.cc index 45c73a3e190..2f06d468d64 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2030,6 +2030,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) thd_proc_info(thd, "Waiting for master update"); thd->version=refresh_version; thd->set_time(); + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; DBUG_RETURN(0); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c3cdcad70f3..c6bf0e381fb 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2828,7 +2828,7 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables) and open and lock them before executing instructions core function. */ if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE) - || open_and_lock_tables(thd, tables)) + || open_and_lock_tables(thd, tables, TRUE, 0)) result= -1; else result= 0; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fb257a6e5ec..86f62d9bf72 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -675,7 +675,7 @@ my_bool acl_reload(THD *thd) tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY; init_mdl_requests(tables); - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { /* Execution might have been interrupted; only print the error message @@ -1602,7 +1602,7 @@ bool change_password(THD *thd, const char *host, const char *user, } #endif - if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(1); mysql_mutex_lock(&acl_cache->lock); @@ -3040,7 +3040,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, class LEX_COLUMN *column; List_iterator <LEX_COLUMN> column_iter(columns); - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); while ((column = column_iter++)) @@ -3146,7 +3146,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, */ Query_tables_list backup; thd->lex->reset_n_backup_query_tables_list(&backup); - if (simple_open_n_lock_tables(thd,tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ @@ -3374,7 +3374,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } #endif - if (simple_open_n_lock_tables(thd,tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen close_thread_tables(thd); /* Restore the state of binlog format */ @@ -3531,7 +3531,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, } #endif - if (simple_open_n_lock_tables(thd,tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ @@ -3853,7 +3853,7 @@ static my_bool grant_reload_procs_priv(THD *thd) TL_READ); table.open_type= OT_BASE_ONLY; - if (simple_open_n_lock_tables(thd, &table)) + if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { close_thread_tables(thd); DBUG_RETURN(TRUE); @@ -3924,7 +3924,7 @@ my_bool grant_reload(THD *thd) To avoid deadlocks we should obtain table locks before obtaining LOCK_grant rwlock. */ - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) goto end; mysql_rwlock_wrlock(&LOCK_grant); @@ -5227,7 +5227,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) } #endif - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen close_thread_tables(thd); DBUG_RETURN(-1); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 63b6a168590..b4c9aa576d0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -122,7 +122,8 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry); static bool auto_repair_table(THD *thd, TABLE_LIST *table_list); static void free_cache_entry(TABLE *entry); static bool tdc_wait_for_old_versions(THD *thd, - MDL_request_list *mdl_requests); + MDL_request_list *mdl_requests, + ulong timeout); static bool has_write_table_with_auto_increment(TABLE_LIST *tables); @@ -2364,8 +2365,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list, mdl_requests.push_front(mdl_request); mdl_requests.push_front(global_request); - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + if (thd->mdl_context.acquire_locks(&mdl_requests, ot_ctx->get_timeout())) return 1; } else @@ -2557,16 +2557,6 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, (int) table_list->lock_type); /* - If we are performing DDL operation we also should ensure - that we will find TABLE instance with upgradable metadata - lock, - */ - if ((flags & MYSQL_OPEN_TAKE_UPGRADABLE_MDL) && - table_list->lock_type >= TL_WRITE_ALLOW_WRITE && - ! table->mdl_ticket->is_upgradable_or_exclusive()) - distance= -1; - - /* Find a table that either has the exact lock type requested, or has the best suitable lock. In case there is no locked table that has an equal or higher lock than requested, @@ -2599,13 +2589,6 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, } if (best_table) { - if ((flags & MYSQL_OPEN_TAKE_UPGRADABLE_MDL) && - table_list->lock_type >= TL_WRITE_ALLOW_WRITE && - ! best_table->mdl_ticket->is_upgradable_or_exclusive()) - { - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), alias); - DBUG_RETURN(TRUE); - } table= best_table; table->query_id= thd->query_id; DBUG_PRINT("info",("Using locked table")); @@ -3309,7 +3292,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) bool Locked_tables_list::reopen_tables(THD *thd) { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); bool lt_refresh_unused; size_t reopen_count= 0; MYSQL_LOCK *lock; @@ -3745,13 +3728,14 @@ end_with_lock_open: /** Open_table_context */ -Open_table_context::Open_table_context(THD *thd) +Open_table_context::Open_table_context(THD *thd, ulong timeout) :m_action(OT_NO_ACTION), m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()), m_has_locks((thd->in_multi_stmt_transaction() && thd->mdl_context.has_locks()) || thd->mdl_context.trans_sentinel()), - m_global_mdl_request(NULL) + m_global_mdl_request(NULL), + m_timeout(timeout) {} @@ -3846,11 +3830,10 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, switch (m_action) { case OT_WAIT_MDL_LOCK: - result= thd->mdl_context.wait_for_lock(mdl_request, - thd->variables.lock_wait_timeout); + result= thd->mdl_context.wait_for_lock(mdl_request, get_timeout()); break; case OT_WAIT_TDC: - result= tdc_wait_for_old_versions(thd, &m_mdl_requests); + result= tdc_wait_for_old_versions(thd, &m_mdl_requests, get_timeout()); DBUG_ASSERT(thd->mysys_var->current_mutex == NULL); break; case OT_DISCOVER: @@ -3867,8 +3850,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, mdl_requests.push_front(&mdl_global_request); if ((result= - thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout))) + thd->mdl_context.acquire_locks(&mdl_requests, get_timeout()))) break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); @@ -3900,8 +3882,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, mdl_requests.push_front(&mdl_global_request); if ((result= - thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout))) + thd->mdl_context.acquire_locks(&mdl_requests, get_timeout()))) break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); @@ -4357,7 +4338,8 @@ end: /** Acquire upgradable (SNW, SNRW) metadata locks on tables to be opened - for LOCK TABLES or a DDL statement. + for LOCK TABLES or a DDL statement. Under LOCK TABLES, we can't take + new locks, so use open_tables_check_upgradable_mdl() instead. @param thd Thread context. @param tables_start Start of list of tables on which upgradable locks @@ -4377,12 +4359,16 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, MDL_request_list mdl_requests; TABLE_LIST *table; + DBUG_ASSERT(!thd->locked_tables_mode); DEBUG_SYNC(thd, "open_tables_acquire_upgradable_mdl"); for (table= tables_start; table && table != tables_end; table= table->next_global) { - if (table->lock_type >= TL_WRITE_ALLOW_WRITE) + if (table->lock_type >= TL_WRITE_ALLOW_WRITE && + !(table->open_type == OT_TEMPORARY_ONLY || + (table->open_type != OT_BASE_ONLY && + find_temporary_table(thd, table)))) { table->mdl_request.set_type(table->lock_type > TL_WRITE_ALLOW_READ ? MDL_SHARED_NO_READ_WRITE : @@ -4400,8 +4386,7 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, mdl_requests.push_front(global_request); } - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + if (thd->mdl_context.acquire_locks(&mdl_requests, ot_ctx->get_timeout())) return TRUE; for (table= tables_start; table && table != tables_end; @@ -4419,6 +4404,58 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, /** + Check for upgradable (SNW, SNRW) metadata locks on tables to be opened + for a DDL statement. Under LOCK TABLES, we can't take new locks, so we + must check if appropriate locks were pre-acquired. + + @param thd Thread context. + @param tables_start Start of list of tables on which upgradable locks + should be searched for. + @param tables_end End of list of tables. + + @retval FALSE Success. + @retval TRUE Failure (e.g. connection was killed) +*/ + +static bool +open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, + TABLE_LIST *tables_end) +{ + TABLE_LIST *table; + + DBUG_ASSERT(thd->locked_tables_mode); + + for (table= tables_start; table && table != tables_end; + table= table->next_global) + { + if (table->lock_type >= TL_WRITE_ALLOW_WRITE && + !(table->open_type == OT_TEMPORARY_ONLY || + (table->open_type != OT_BASE_ONLY && + find_temporary_table(thd, table)))) + { + /* + We don't need to do anything about the found TABLE instance as it + will be handled later in open_tables(), we only need to check that + an upgradable lock is already acquired. When we enter LOCK TABLES + mode, SNRW locks are acquired before all other locks. So if under + LOCK TABLES we find that there is TABLE instance with upgradeable + lock, all other instances of TABLE for the same table will have the + same ticket. + + Note that find_table_for_mdl_upgrade() will report an error if a + ticket is not found. + */ + if (!find_table_for_mdl_upgrade(thd->open_tables, table->db, + table->table_name, FALSE)) + return TRUE; + } + } + + return FALSE; +} + + +/** Open all tables in list @param[in] thd Thread context. @@ -4460,7 +4497,8 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags, TABLE_LIST **table_to_open; Sroutine_hash_entry **sroutine_to_open; TABLE_LIST *tables; - Open_table_context ot_ctx(thd); + Open_table_context ot_ctx(thd, (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? + LONG_TIMEOUT : thd->variables.lock_wait_timeout); bool error= FALSE; MEM_ROOT new_frm_mem; bool has_prelocking_list; @@ -4503,12 +4541,31 @@ restart: lock will be reused (thanks to the fact that in recursive case metadata locks are acquired without waiting). */ - if ((flags & MYSQL_OPEN_TAKE_UPGRADABLE_MDL) && - ! thd->locked_tables_mode) + if (flags & MYSQL_OPEN_TAKE_UPGRADABLE_MDL) { - if (open_tables_acquire_upgradable_mdl(thd, *start, - thd->lex->first_not_own_table(), - &ot_ctx)) + /* + open_tables_acquire_upgradable_mdl() does not currenly handle + these two flags. At this point, that does not matter as they + are not used together with MYSQL_OPEN_TAKE_UPGRADABLE_MDL. + */ + DBUG_ASSERT(!(flags & (MYSQL_OPEN_SKIP_TEMPORARY | + MYSQL_OPEN_TEMPORARY_ONLY))); + if (thd->locked_tables_mode) + { + /* + Under LOCK TABLES, we can't acquire new locks, so we instead + need to check if appropriate locks were pre-acquired. + */ + if (open_tables_check_upgradable_mdl(thd, *start, + thd->lex->first_not_own_table())) + { + error= TRUE; + goto err; + } + } + else if (open_tables_acquire_upgradable_mdl(thd, *start, + thd->lex->first_not_own_table(), + &ot_ctx)) { error= TRUE; goto err; @@ -4964,7 +5021,7 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, table_l->required_type= FRMTYPE_TABLE; /* Open the table. */ - if (open_and_lock_tables_derived(thd, table_l, FALSE, flags)) + if (open_and_lock_tables(thd, table_l, FALSE, flags)) table_l->table= NULL; /* Just to be sure. */ /* Restore list. */ @@ -5002,7 +5059,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, uint lock_flags) { TABLE *table; - Open_table_context ot_ctx(thd); + Open_table_context ot_ctx(thd, (lock_flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? + LONG_TIMEOUT : thd->variables.lock_wait_timeout); bool refresh; bool error; DBUG_ENTER("open_ltable"); @@ -5101,20 +5159,13 @@ end: @note The lock will automaticaly be freed by close_thread_tables() - @note - There are several convenience functions, e.g. : - - simple_open_n_lock_tables(thd, tables) without derived handling - - open_and_lock_tables(thd, tables) with derived handling - Both inline functions call open_and_lock_tables_derived() with - the third argument set appropriately. - @retval FALSE OK. @retval TRUE Error */ -bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, - bool derived, uint flags, - Prelocking_strategy *prelocking_strategy) +bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, + bool derived, uint flags, + Prelocking_strategy *prelocking_strategy) { uint counter; bool need_reopen; @@ -5128,7 +5179,7 @@ bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, statement. */ MDL_ticket *start_of_statement_svp= thd->mdl_context.mdl_savepoint(); - DBUG_ENTER("open_and_lock_tables_derived"); + DBUG_ENTER("open_and_lock_tables"); DBUG_PRINT("enter", ("derived handling: %d", derived)); for ( ; ; ) @@ -8539,16 +8590,18 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, @param thd Thread context @param context Metadata locking context with locks. + @param timeout Seconds to wait before reporting ER_LOCK_WAIT_TIMEOUT. */ static bool -tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests) +tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests, + ulong timeout) { TABLE_SHARE *share; const char *old_msg; MDL_request *mdl_request; struct timespec abstime; - set_timespec(abstime, thd->variables.lock_wait_timeout); + set_timespec(abstime, timeout); int wait_result= 0; while (!thd->killed) @@ -8815,8 +8868,9 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, lex->reset_n_backup_query_tables_list(&query_tables_list_backup); thd->reset_n_backup_open_tables_state(backup); - if (open_and_lock_tables_derived(thd, table_list, FALSE, - MYSQL_LOCK_IGNORE_FLUSH)) + if (open_and_lock_tables(thd, table_list, FALSE, + MYSQL_LOCK_IGNORE_FLUSH | + MYSQL_LOCK_IGNORE_TIMEOUT)) { lex->restore_backup_query_tables_list(&query_tables_list_backup); goto error; @@ -8878,7 +8932,8 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table) { DBUG_ENTER("open_system_table_for_update"); - TABLE *table= open_ltable(thd, one_table, one_table->lock_type, 0); + TABLE *table= open_ltable(thd, one_table, one_table->lock_type, + MYSQL_LOCK_IGNORE_TIMEOUT); if (table) { DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM); @@ -8905,6 +8960,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY | MYSQL_LOCK_IGNORE_FLUSH | + MYSQL_LOCK_IGNORE_TIMEOUT | MYSQL_LOCK_PERF_SCHEMA); TABLE *table; /* Save value that is changed in mysql_lock_tables() */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 98b502c0d19..538a8a42ef6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1280,7 +1280,7 @@ public: OT_DISCOVER, OT_REPAIR }; - Open_table_context(THD *thd); + Open_table_context(THD *thd, ulong timeout); bool recover_from_failed_open(THD *thd, MDL_request *mdl_request, TABLE_LIST *table); @@ -1305,6 +1305,11 @@ public: MDL_request *get_global_mdl_request(THD *thd); + inline ulong get_timeout() const + { + return m_timeout; + } + private: /** List of requests for all locks taken so far. Used for waiting on locks. */ MDL_request_list m_mdl_requests; @@ -1322,6 +1327,11 @@ private: opening tables for statements which take upgradable shared metadata locks. */ MDL_request *m_global_mdl_request; + /** + Lock timeout in seconds. Initialized to LONG_TIMEOUT when opening system + tables or to the "lock_wait_timeout" system variable for regular tables. + */ + uint m_timeout; }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ea466da8ea1..2c3242c10cd 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -57,7 +57,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, THD::STMT_QUERY_TYPE : THD::ROW_QUERY_TYPE; - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); if (!(table= table_list->table)) { diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 4a69b46ddb7..3afeb4164bd 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -311,7 +311,11 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) if (!reopen) my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); else + { hash_tables->table= NULL; + /* Safety, cleanup the pointer to satisfy MDL assertions. */ + hash_tables->mdl_request.ticket= NULL; + } DBUG_PRINT("exit",("ERROR")); DBUG_RETURN(TRUE); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 45c9c0363dd..ddf7dcb22d0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -545,7 +545,7 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) Open tables used for sub-selects or in stored functions, will also cache these functions. */ - if (open_and_lock_tables(thd, table_list->next_global)) + if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0)) { end_delayed_insert(thd); DBUG_RETURN(TRUE); @@ -569,7 +569,7 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) Use a normal insert. */ table_list->lock_type= TL_WRITE; - DBUG_RETURN(open_and_lock_tables(thd, table_list)); + DBUG_RETURN(open_and_lock_tables(thd, table_list, TRUE, 0)); } @@ -646,7 +646,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } else { - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); } lock_type= table_list->lock_type; @@ -3619,7 +3619,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); /* Here we open the destination table, on which we already have an exclusive metadata lock. @@ -3638,7 +3638,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } else { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); if (open_table(thd, create_table, thd->mem_root, &ot_ctx_unused, MYSQL_OPEN_TEMPORARY_ONLY)) { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1eabce0b474..3f49543c69d 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -195,7 +195,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED)); } - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 714e3af5296..7a13c46e4f6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -325,6 +325,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_PRELOAD_KEYS]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS; } @@ -1587,6 +1588,113 @@ 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. + + 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) +*/ + +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)) + goto error; + + 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)) + { + close_thread_tables(thd); + goto error; + } + + /* + 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. @@ -2077,7 +2185,7 @@ case SQLCOM_PREPARE: } case SQLCOM_DO: if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) - || open_and_lock_tables(thd, all_tables)) + || open_and_lock_tables(thd, all_tables, TRUE, 0)) goto error; res= mysql_do(thd, *lex->insert_list); @@ -2414,7 +2522,7 @@ case SQLCOM_PREPARE: create_table->open_type= OT_BASE_ONLY; } - if (!(res= open_and_lock_tables_derived(thd, lex->query_tables, TRUE, 0))) + if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0))) { /* Is table which we are changing used somewhere in other parts @@ -3007,7 +3115,7 @@ end_with_restore_list: unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, all_tables))) + if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) { MYSQL_INSERT_SELECT_START(thd->query()); /* Skip first table, which is the table we are inserting in */ @@ -3109,7 +3217,7 @@ end_with_restore_list: goto error; thd_proc_info(thd, "init"); - if ((res= open_and_lock_tables(thd, all_tables))) + if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) break; MYSQL_MULTI_DELETE_START(thd->query()); @@ -3237,7 +3345,7 @@ end_with_restore_list: List<set_var_base> *lex_var_list= &lex->var_list; if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) - || open_and_lock_tables(thd, all_tables))) + || open_and_lock_tables(thd, all_tables, TRUE, 0))) goto error; if (!(res= sql_set_variables(thd, lex_var_list))) { @@ -3303,9 +3411,9 @@ end_with_restore_list: { Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; - res= (open_and_lock_tables_derived(thd, all_tables, FALSE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL, - &lock_tables_prelocking_strategy) || + res= (open_and_lock_tables(thd, all_tables, FALSE, + MYSQL_OPEN_TAKE_UPGRADABLE_MDL, + &lock_tables_prelocking_strategy) || thd->locked_tables_list.init_locked_tables(thd)); } @@ -3727,9 +3835,18 @@ end_with_restore_list: case SQLCOM_FLUSH: { bool write_to_binlog; + if (check_global_access(thd,RELOAD_ACL)) goto error; + if (first_table && lex->type & REFRESH_READ_LOCK) + { + if (flush_tables_with_read_lock(thd, all_tables)) + goto error; + my_ok(thd); + break; + } + /* reload_acl_and_cache() will tell us if we are allowed to write to the binlog or not. @@ -4008,7 +4125,7 @@ create_sp_error: */ if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) || - open_and_lock_tables(thd, all_tables)) + open_and_lock_tables(thd, all_tables, TRUE, 0)) goto error; /* @@ -4523,7 +4640,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) param->select_limit= new Item_int((ulonglong) thd->variables.select_limit); } - if (!(res= open_and_lock_tables(thd, all_tables))) + if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) { if (lex->describe) { diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index f0d9560dff4..3d1380d46f3 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1469,7 +1469,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) goto end; #endif /* EMBEDDED_LIBRARY */ - if (simple_open_n_lock_tables(new_thd, &tables)) + if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { DBUG_PRINT("error",("Can't open plugin table")); sql_print_error("Can't open the mysql.plugin table. Please " @@ -1746,7 +1746,8 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table = open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table = open_ltable(thd, &tables, TL_WRITE, + MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_plugin); @@ -1817,7 +1818,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_plugin); diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 0af076d6102..0bf38639ff7 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -253,7 +253,7 @@ bool servers_reload(THD *thd) tables[0].init_one_table("mysql", 5, "servers", 7, "servers", TL_READ); - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { /* Execution might have been interrupted; only print the error message @@ -390,7 +390,7 @@ insert_server(THD *thd, FOREIGN_SERVER *server) tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE); /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) goto end; /* insert the server into the table */ @@ -611,7 +611,7 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) if ((error= delete_server_record_in_cache(server_options))) goto end; - if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) { error= my_errno; goto end; @@ -728,7 +728,7 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE); - if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) { error= my_errno; goto end; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3c6b4760fd3..8ba8c50b01e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4225,8 +4225,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, /* Open or obtain an exclusive metadata lock on table being created. */ - if (open_and_lock_tables_derived(thd, thd->lex->query_tables, FALSE, - 0)) + if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { result= TRUE; goto unlock; @@ -4425,7 +4424,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, char from[FN_REFLEN],tmp[FN_REFLEN+32]; const char **ext; MY_STAT stat_info; - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); DBUG_ENTER("prepare_for_repair"); uint reopen_for_repair_flags= (MYSQL_LOCK_IGNORE_FLUSH | MYSQL_OPEN_HAS_MDL_LOCK); @@ -4677,8 +4676,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - open_error= open_and_lock_tables_derived(thd, table, TRUE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL); + open_error= open_and_lock_tables(thd, table, TRUE, + MYSQL_OPEN_TAKE_UPGRADABLE_MDL); thd->no_warnings_for_error= 0; table->next_global= save_next_global; table->next_local= save_next_local; @@ -5347,7 +5346,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, char buf[2048]; String query(buf, sizeof(buf), system_charset_info); query.length(0); // Have to zero it since constructor doesn't - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); /* The condition avoids a crash as described in BUG#48506. Other @@ -6556,9 +6555,9 @@ view_err: Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info); - error= open_and_lock_tables_derived(thd, table_list, FALSE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL, - &alter_prelocking_strategy); + error= open_and_lock_tables(thd, table_list, FALSE, + MYSQL_OPEN_TAKE_UPGRADABLE_MDL, + &alter_prelocking_strategy); if (error) { @@ -7149,7 +7148,7 @@ view_err: { if (table->s->tmp_table) { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); TABLE_LIST tbl; bzero((void*) &tbl, sizeof(tbl)); tbl.db= new_db; @@ -7435,7 +7434,7 @@ view_err: To do this we need to obtain a handler object for it. NO need to tamper with MERGE tables. The real open is done later. */ - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); TABLE *t_table; if (new_name != table_name || new_db != db) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 3bead5217f0..7dfcf9f6b2e 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -163,7 +163,7 @@ void udf_init() tables.init_one_table(db, sizeof(db)-1, "func", 4, "func", TL_READ); - if (simple_open_n_lock_tables(new_thd, &tables)) + if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { DBUG_PRINT("error",("Can't open udf table")); sql_print_error("Can't open the mysql.func table. Please " @@ -505,7 +505,7 @@ int mysql_create_function(THD *thd,udf_func *udf) tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE); /* Allow creation of functions even if we can't open func table */ - if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) goto err; table->use_all_columns(); restore_record(table, s->default_values); // Default values for fields @@ -596,7 +596,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE); - if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) goto err; table->use_all_columns(); table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 60971f51154..4438f1c37b5 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -396,7 +396,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, view->lock_strategy= TABLE_LIST::EXCLUSIVE_MDL; view->open_type= OT_BASE_ONLY; - if (open_and_lock_tables(thd, lex->query_tables)) + if (open_and_lock_tables(thd, lex->query_tables, TRUE, 0)) { view= lex->unlink_first_table(&link_to_local); res= TRUE; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f03694cb359..5648e3cbdb5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -767,10 +767,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 169 shift/reduce conflicts. + Currently there are 168 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 169 +%expect 168 /* Comments for TOKENS. @@ -1554,6 +1554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list clear_privileges flush_options flush_option + opt_with_read_lock flush_options_list equal optional_braces opt_mi_check_type opt_to mi_check_types normal_join table_to_table_list table_to_table opt_table_list opt_as @@ -11095,17 +11096,27 @@ flush: ; flush_options: - flush_options ',' flush_option + table_or_tables + { Lex->type|= REFRESH_TABLES; } + opt_table_list {} + opt_with_read_lock {} + | flush_options_list + ; + +opt_with_read_lock: + /* empty */ {} + | WITH READ_SYM LOCK_SYM + { Lex->type|= REFRESH_READ_LOCK; } + ; + +flush_options_list: + flush_options_list ',' flush_option | flush_option + {} ; flush_option: - table_or_tables - { Lex->type|= REFRESH_TABLES; } - opt_table_list {} - | TABLES WITH READ_SYM LOCK_SYM - { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; } - | ERROR_SYM LOGS_SYM + ERROR_SYM LOGS_SYM { Lex->type|= REFRESH_ERROR_LOG; } | ENGINE_SYM LOGS_SYM { Lex->type|= REFRESH_ENGINE_LOG; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index ba970925fc6..80eee89c8a9 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1305,6 +1305,17 @@ static Sys_var_ulong Sys_optimizer_prune_level( SESSION_VAR(optimizer_prune_level), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1), DEFAULT(1), BLOCK_SIZE(1)); +/** Warns about deprecated value 63 */ +static bool fix_optimizer_search_depth(sys_var *self, THD *thd, + enum_var_type type) +{ + SV *sv= type == OPT_GLOBAL ? &global_system_variables : &thd->variables; + if (sv->optimizer_search_depth == MAX_TABLES+2) + WARN_DEPRECATED(thd, 6, 0, "optimizer-search-depth=63", + "a search depth less than 63"); + return false; +} + static Sys_var_ulong Sys_optimizer_search_depth( "optimizer_search_depth", "Maximum depth of search performed by the query optimizer. Values " @@ -1313,10 +1324,12 @@ static Sys_var_ulong Sys_optimizer_search_depth( "than the number of tables in a relation result in faster " "optimization, but may produce very bad query plans. If set to 0, " "the system will automatically pick a reasonable value; if set to " - "63, the optimizer will switch to the original find_best search" - "(used for testing/comparison)", + "63, the optimizer will switch to the original find_best search. " + "NOTE: The value 63 and its associated behaviour is deprecated", SESSION_VAR(optimizer_search_depth), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(0, MAX_TABLES+2), DEFAULT(MAX_TABLES+1), BLOCK_SIZE(1)); + VALID_RANGE(0, MAX_TABLES+2), DEFAULT(MAX_TABLES+1), BLOCK_SIZE(1), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(fix_optimizer_search_depth)); static const char *optimizer_switch_names[]= { @@ -2795,7 +2808,7 @@ static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type) mysql_mutex_unlock(&LOCK_active_mi); return false; } -static Sys_var_ulong Sys_slave_net_timeout( +static Sys_var_uint Sys_slave_net_timeout( "slave_net_timeout", "Number of seconds to wait for more data " "from a master/slave connection before aborting the read", GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG), diff --git a/sql/tztime.cc b/sql/tztime.cc index 01450c9bae3..632dca1ce44 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1667,8 +1667,8 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) We need to open only mysql.time_zone_leap_second, but we try to open all time zone tables to see if they exist. */ - if (open_and_lock_tables_derived(thd, tz_tables, FALSE, - MYSQL_LOCK_IGNORE_FLUSH)) + if (open_and_lock_tables(thd, tz_tables, FALSE, + MYSQL_LOCK_IGNORE_FLUSH | MYSQL_LOCK_IGNORE_TIMEOUT)) { sql_print_warning("Can't open and lock time zone table: %s " "trying to live without them", thd->stmt_da->message()); diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc index c824b93093e..d0f5315ff36 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.cc @@ -128,7 +128,7 @@ void PFS_engine_table_share::check_one_table(THD *thd) thd->lex= &dummy_lex; lex_start(thd); - if (! simple_open_n_lock_tables(thd, &tables)) + if (! open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { PFS_check_intact checker; diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index 2ce3a844290..28b54cc6979 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -66,7 +66,7 @@ ulong events_waits_history_per_thread; /** Number of instruments class per thread. */ ulong instr_class_per_thread; /** Number of locker lost. @sa LOCKER_STACK_SIZE. */ -ulong locker_lost; +ulong locker_lost= 0; /** Mutex instrumentation instances array. @@ -746,8 +746,23 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, } } - if (len >= sizeof(pfs->m_filename)) - len= sizeof(pfs->m_filename) - 1; + /* + Normalize the file name to avoid duplicates when using aliases: + - absolute or relative paths + - symbolic links + */ + char buffer[FN_REFLEN]; + const char *normalized_filename; + int normalized_length; + + /* + Ignore errors, the file may not exist. + my_realpath always provide a best effort result in buffer. + */ + (void) my_realpath(buffer, filename, MYF(0)); + + normalized_filename= buffer; + normalized_length= strlen(normalized_filename); PFS_file **entry; uint retry_count= 0; @@ -755,7 +770,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, search: entry= reinterpret_cast<PFS_file**> (lf_hash_search(&filename_hash, thread->m_filename_hash_pins, - filename, len)); + normalized_filename, normalized_length)); if (entry && (entry != MY_ERRPTR)) { pfs= *entry; @@ -783,9 +798,9 @@ search: if (pfs->m_lock.free_to_dirty()) { pfs->m_class= klass; - strncpy(pfs->m_filename, filename, len); - pfs->m_filename[len]= '\0'; - pfs->m_filename_length= len; + strncpy(pfs->m_filename, normalized_filename, normalized_length); + pfs->m_filename[normalized_length]= '\0'; + pfs->m_filename_length= normalized_length; pfs->m_file_stat.m_open_count= 1; pfs->m_wait_stat.m_control_flag= &flag_events_waits_summary_by_instance; |