Commit 01ee0f96 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

merge

parents 75b72ce7 5a05c470
......@@ -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)
......
......@@ -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
......
......@@ -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)
......
......@@ -2266,7 +2266,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 \
......
......@@ -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
......
......@@ -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;
......@@ -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
......
......@@ -396,8 +396,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,
......
......@@ -396,8 +396,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,
......
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;
#
# 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;
......@@ -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
......@@ -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%";
......@@ -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
......
......@@ -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;
......@@ -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) */
......@@ -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
......
......@@ -148,10 +148,37 @@ class MDL_lock
/**
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 @@ class MDL_lock
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);
}
......
......@@ -624,10 +624,11 @@ class MDL_context
/**
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 @@ class MDL_context
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 @@ class MDL_context
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()
......
......@@ -1965,7 +1965,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;
......
......@@ -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;
......
......@@ -1587,6 +1587,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.
......@@ -3728,9 +3835,18 @@ case SQLCOM_PREPARE:
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.
......
......@@ -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; }
......
......@@ -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),
......
......@@ -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 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment