mirror of
https://github.com/MariaDB/server.git
synced 2025-07-01 03:26:54 +03:00
Changed FLUSH TABLES to not change share version
Part of MDEV-5336 Implement LOCK FOR BACKUP Originally both table metadata lock and global read lock protection were acquired before getting TABLE from table cache. This will be reordered in a future commit with MDL_BACKUP_XXX locks so that we first take table metadata lock, then get TABLE from table cache, then acquire analogue of global read lock. This patch both simplifies FLUSH TABLES code, makes FLUSH TABLES to lock less and also enables FLUSH TABLES code to be used with backup locks. The usage of FLUSH TABLES changes slightly: - FLUSH TABLES without any arguments will now only close not used tables and tables locked by the FLUSH TABLES connection. All not used table shares will be closed. Tables locked by the FLUSH TABLES connection will be reopened and re-locked after all others has stoped using the table (as before). If there was no locked tables, then FLUSH TABLES is instant and will not cause any waits. FLUSH TABLES will not wait for any in use table. - FLUSH TABLES with a table list, will ensure that the tables are closed before statement returns. The code is now only using MDL locks and not table share versions, which simplices the code greatly. One visible change is that the server will wait for the end of the transaction that are using the tables. Before FLUSH TABLES only waited for the statements to end. Signed-off-by: Monty <monty@mariadb.org>
This commit is contained in:
@ -364,16 +364,19 @@ flush table t1;
|
|||||||
connection default;
|
connection default;
|
||||||
# Let flush table sync in.
|
# Let flush table sync in.
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
a
|
||||||
connection con1;
|
connection con1;
|
||||||
select * from t1;
|
select * from t1;
|
||||||
a
|
a
|
||||||
unlock tables;
|
unlock tables;
|
||||||
|
connection default;
|
||||||
|
select count(*) from information_schema.processlist where state = "Waiting for table metadata lock";
|
||||||
|
count(*)
|
||||||
|
1
|
||||||
|
commit;
|
||||||
connection con2;
|
connection con2;
|
||||||
# Reaping 'flush table t1'...
|
# Reaping 'flush table t1'...
|
||||||
connection default;
|
connection default;
|
||||||
# Reaping 'select * from t1'...
|
|
||||||
a
|
|
||||||
commit;
|
|
||||||
#
|
#
|
||||||
# Repeat the same test but with FLUSH TABLES
|
# Repeat the same test but with FLUSH TABLES
|
||||||
#
|
#
|
||||||
@ -386,13 +389,10 @@ connection con1;
|
|||||||
#
|
#
|
||||||
lock table t1 read;
|
lock table t1 read;
|
||||||
connection con2;
|
connection con2;
|
||||||
#
|
|
||||||
# FLUSH TABLES expels the table definition from the cache.
|
|
||||||
# Sending 'flush tables'...
|
|
||||||
flush tables;
|
flush tables;
|
||||||
connection default;
|
connection default;
|
||||||
# Let flush table sync in.
|
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
a
|
||||||
connection con1;
|
connection con1;
|
||||||
select * from t1;
|
select * from t1;
|
||||||
a
|
a
|
||||||
@ -400,8 +400,6 @@ unlock tables;
|
|||||||
connection con2;
|
connection con2;
|
||||||
# Reaping 'flush tables'...
|
# Reaping 'flush tables'...
|
||||||
connection default;
|
connection default;
|
||||||
# Reaping 'select * from t1'...
|
|
||||||
a
|
|
||||||
commit;
|
commit;
|
||||||
# Cleanup
|
# Cleanup
|
||||||
connection con1;
|
connection con1;
|
||||||
|
@ -449,24 +449,20 @@ connection default;
|
|||||||
--echo # Let flush table sync in.
|
--echo # Let flush table sync in.
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
select count(*) = 1 from information_schema.processlist
|
select count(*) = 1 from information_schema.processlist
|
||||||
where state = "Waiting for table flush"
|
where state = "Waiting for table metadata lock"
|
||||||
and info = "flush table t1";
|
and info = "flush table t1";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
send select * from t1;
|
select * from t1;
|
||||||
connection con1;
|
connection con1;
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table flush"
|
|
||||||
and info = "select * from t1";
|
|
||||||
select * from t1;
|
select * from t1;
|
||||||
unlock tables;
|
unlock tables;
|
||||||
|
connection default;
|
||||||
|
select count(*) from information_schema.processlist where state = "Waiting for table metadata lock";
|
||||||
|
commit;
|
||||||
connection con2;
|
connection con2;
|
||||||
--echo # Reaping 'flush table t1'...
|
--echo # Reaping 'flush table t1'...
|
||||||
reap;
|
reap;
|
||||||
connection default;
|
connection default;
|
||||||
--echo # Reaping 'select * from t1'...
|
|
||||||
reap;
|
|
||||||
commit;
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Repeat the same test but with FLUSH TABLES
|
--echo # Repeat the same test but with FLUSH TABLES
|
||||||
@ -480,31 +476,16 @@ connection con1;
|
|||||||
--echo #
|
--echo #
|
||||||
lock table t1 read;
|
lock table t1 read;
|
||||||
connection con2;
|
connection con2;
|
||||||
--echo #
|
|
||||||
--echo # FLUSH TABLES expels the table definition from the cache.
|
|
||||||
--echo # Sending 'flush tables'...
|
|
||||||
send flush tables;
|
send flush tables;
|
||||||
connection default;
|
connection default;
|
||||||
--echo # Let flush table sync in.
|
select * from t1;
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table flush"
|
|
||||||
and info = "flush tables";
|
|
||||||
--source include/wait_condition.inc
|
|
||||||
send select * from t1;
|
|
||||||
connection con1;
|
connection con1;
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table flush"
|
|
||||||
and info = "select * from t1";
|
|
||||||
select * from t1;
|
select * from t1;
|
||||||
unlock tables;
|
unlock tables;
|
||||||
connection con2;
|
connection con2;
|
||||||
--echo # Reaping 'flush tables'...
|
--echo # Reaping 'flush tables'...
|
||||||
reap;
|
reap;
|
||||||
connection default;
|
connection default;
|
||||||
--echo # Reaping 'select * from t1'...
|
|
||||||
reap;
|
|
||||||
commit;
|
commit;
|
||||||
|
|
||||||
--echo # Cleanup
|
--echo # Cleanup
|
||||||
|
@ -1957,6 +1957,7 @@ lock table t1 read;
|
|||||||
connect con1, localhost, root,,;
|
connect con1, localhost, root,,;
|
||||||
connection con1;
|
connection con1;
|
||||||
flush tables;
|
flush tables;
|
||||||
|
flush tables t1;
|
||||||
connection default;
|
connection default;
|
||||||
select * from information_schema.views;
|
select * from information_schema.views;
|
||||||
TABLE_CATALOG def
|
TABLE_CATALOG def
|
||||||
|
@ -1622,12 +1622,13 @@ alter table t1 change b c int;
|
|||||||
lock table t1 read;
|
lock table t1 read;
|
||||||
connect(con1, localhost, root,,);
|
connect(con1, localhost, root,,);
|
||||||
connection con1;
|
connection con1;
|
||||||
send flush tables;
|
flush tables;
|
||||||
|
send flush tables t1;
|
||||||
connection default;
|
connection default;
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
select count(*) = 1 from information_schema.processlist
|
select count(*) = 1 from information_schema.processlist
|
||||||
where state = "Waiting for table flush" and
|
where state = "Waiting for table metadata lock" and
|
||||||
info = "flush tables";
|
info = "flush tables t1";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
--vertical_results
|
--vertical_results
|
||||||
select * from information_schema.views;
|
select * from information_schema.views;
|
||||||
|
@ -324,7 +324,7 @@ connection blocker;
|
|||||||
lock tables t1 read;
|
lock tables t1 read;
|
||||||
connection ddl;
|
connection ddl;
|
||||||
# Let us mark locked table t1 as old
|
# Let us mark locked table t1 as old
|
||||||
flush tables;
|
flush tables t1;
|
||||||
connection dml;
|
connection dml;
|
||||||
select * from t1;
|
select * from t1;
|
||||||
connection default;
|
connection default;
|
||||||
|
@ -538,18 +538,18 @@ connection blocker;
|
|||||||
lock tables t1 read;
|
lock tables t1 read;
|
||||||
connection ddl;
|
connection ddl;
|
||||||
--echo # Let us mark locked table t1 as old
|
--echo # Let us mark locked table t1 as old
|
||||||
--send flush tables
|
--send flush tables t1
|
||||||
connection dml;
|
connection dml;
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
select count(*) = 1 from information_schema.processlist
|
select count(*) = 1 from information_schema.processlist
|
||||||
where state = "Waiting for table flush" and
|
where state = "Waiting for table metadata lock" and
|
||||||
info = "flush tables";
|
info = "flush tables t1";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
--send select * from t1
|
--send select * from t1
|
||||||
connection default;
|
connection default;
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
select count(*) = 1 from information_schema.processlist
|
select count(*) = 1 from information_schema.processlist
|
||||||
where state = "Waiting for table flush" and
|
where state = "Waiting for table metadata lock" and
|
||||||
info = "select * from t1";
|
info = "select * from t1";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
--replace_result $ID2 ID2
|
--replace_result $ID2 ID2
|
||||||
|
@ -500,7 +500,7 @@ connect con1,localhost,root,,test;
|
|||||||
LOCK TABLE t2 WRITE;
|
LOCK TABLE t2 WRITE;
|
||||||
SET lock_wait_timeout= 1;
|
SET lock_wait_timeout= 1;
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
FLUSH TABLES t2;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
connection default;
|
connection default;
|
||||||
|
@ -609,8 +609,8 @@ LOCK TABLE t1 READ;
|
|||||||
--connect (con1,localhost,root,,test)
|
--connect (con1,localhost,root,,test)
|
||||||
LOCK TABLE t2 WRITE;
|
LOCK TABLE t2 WRITE;
|
||||||
SET lock_wait_timeout= 1;
|
SET lock_wait_timeout= 1;
|
||||||
--error ER_LOCK_WAIT_TIMEOUT
|
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
|
FLUSH TABLES t2;
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
@ -531,8 +531,9 @@ connect con3, localhost, root;
|
|||||||
connection default;
|
connection default;
|
||||||
LOCK TABLE t1 READ;
|
LOCK TABLE t1 READ;
|
||||||
connection con3;
|
connection con3;
|
||||||
# Sending:
|
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
|
# Sending:
|
||||||
|
FLUSH TABLES t1;
|
||||||
connection con2;
|
connection con2;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||||
|
@ -931,13 +931,19 @@ connection default;
|
|||||||
LOCK TABLE t1 READ;
|
LOCK TABLE t1 READ;
|
||||||
|
|
||||||
connection con3;
|
connection con3;
|
||||||
|
|
||||||
|
# first test that flush tables doesn't block
|
||||||
|
FLUSH TABLES;
|
||||||
|
|
||||||
|
# Check the FLUSH TABLES t1 waits until table lock is released
|
||||||
|
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
--send FLUSH TABLES
|
--send FLUSH TABLES t1
|
||||||
|
|
||||||
connection con2;
|
connection con2;
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
SELECT COUNT(*) = 1 FROM information_schema.processlist
|
SELECT COUNT(*) = 1 FROM information_schema.processlist
|
||||||
WHERE state = "Waiting for table flush" AND info = "FLUSH TABLES";
|
WHERE state = "Waiting for table metadata lock" AND info = "FLUSH TABLES t1";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
--error ER_LOCK_WAIT_TIMEOUT
|
--error ER_LOCK_WAIT_TIMEOUT
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
|
@ -782,7 +782,7 @@ SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
|||||||
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
||||||
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
||||||
# Sending:
|
# Sending:
|
||||||
FLUSH TABLES;
|
FLUSH TABLES t1;
|
||||||
connection default;
|
connection default;
|
||||||
# Waiting for FLUSH TABLES to be blocked.
|
# Waiting for FLUSH TABLES to be blocked.
|
||||||
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
||||||
|
@ -974,12 +974,12 @@ SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
|||||||
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
||||||
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
--send FLUSH TABLES
|
--send FLUSH TABLES t1
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
--echo # Waiting for FLUSH TABLES to be blocked.
|
--echo # Waiting for FLUSH TABLES to be blocked.
|
||||||
let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist
|
let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist
|
||||||
WHERE state= 'Waiting for table flush' AND info= 'FLUSH TABLES';
|
WHERE state= 'Waiting for table metadata lock' AND info= 'FLUSH TABLES t1';
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
||||||
|
|
||||||
|
@ -2146,10 +2146,11 @@ flush tables t1, t2 with read lock;
|
|||||||
connection con1;
|
connection con1;
|
||||||
# Wait till FLUSH TABLES <list> WITH READ LOCK stops.
|
# Wait till FLUSH TABLES <list> WITH READ LOCK stops.
|
||||||
set debug_sync='now WAIT_FOR parked';
|
set debug_sync='now WAIT_FOR parked';
|
||||||
|
flush tables;
|
||||||
# Start a statement which will flush all tables and thus
|
# Start a statement which will flush all tables and thus
|
||||||
# invalidate table t1 open by FLUSH TABLES <list> WITH READ LOCK.
|
# invalidate table t1 open by FLUSH TABLES <list> WITH READ LOCK.
|
||||||
# Sending:
|
# Sending:
|
||||||
flush tables;
|
flush tables t1;
|
||||||
connection default;
|
connection default;
|
||||||
# Wait till the above FLUSH TABLES blocks.
|
# Wait till the above FLUSH TABLES blocks.
|
||||||
# Resume FLUSH TABLES <list> WITH READ LOCK, so it tries to open t2
|
# Resume FLUSH TABLES <list> WITH READ LOCK, so it tries to open t2
|
||||||
|
@ -2690,17 +2690,20 @@ connection con1;
|
|||||||
--echo # Wait till FLUSH TABLES <list> WITH READ LOCK stops.
|
--echo # Wait till FLUSH TABLES <list> WITH READ LOCK stops.
|
||||||
set debug_sync='now WAIT_FOR parked';
|
set debug_sync='now WAIT_FOR parked';
|
||||||
|
|
||||||
|
# Simple flush tables should not block
|
||||||
|
flush tables;
|
||||||
|
|
||||||
--echo # Start a statement which will flush all tables and thus
|
--echo # Start a statement which will flush all tables and thus
|
||||||
--echo # invalidate table t1 open by FLUSH TABLES <list> WITH READ LOCK.
|
--echo # invalidate table t1 open by FLUSH TABLES <list> WITH READ LOCK.
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
send flush tables;
|
send flush tables t1;
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
--echo # Wait till the above FLUSH TABLES blocks.
|
--echo # Wait till the above FLUSH TABLES blocks.
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
select count(*) = 1 from information_schema.processlist
|
select count(*) = 1 from information_schema.processlist
|
||||||
where state = "Waiting for table flush" and
|
where state = "Waiting for table metadata lock" and
|
||||||
info = "flush tables";
|
info = "flush tables t1";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
--echo # Resume FLUSH TABLES <list> WITH READ LOCK, so it tries to open t2
|
--echo # Resume FLUSH TABLES <list> WITH READ LOCK, so it tries to open t2
|
||||||
|
@ -40,7 +40,7 @@ TRUNCATE TABLE m1;
|
|||||||
connection con2;
|
connection con2;
|
||||||
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
||||||
# Sending:
|
# Sending:
|
||||||
FLUSH TABLES;
|
FLUSH TABLES m1;
|
||||||
connection default;
|
connection default;
|
||||||
# Waiting for FLUSH TABLES to be blocked.
|
# Waiting for FLUSH TABLES to be blocked.
|
||||||
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
||||||
|
@ -81,12 +81,12 @@ SET DEBUG_SYNC= 'open_tables_after_open_and_process_table SIGNAL opened WAIT_FOR
|
|||||||
connection con2;
|
connection con2;
|
||||||
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
--send FLUSH TABLES
|
--send FLUSH TABLES m1
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
--echo # Waiting for FLUSH TABLES to be blocked.
|
--echo # Waiting for FLUSH TABLES to be blocked.
|
||||||
let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist
|
let $wait_condition= SELECT COUNT(*)=1 FROM information_schema.processlist
|
||||||
WHERE state= 'Waiting for table flush' AND info= 'FLUSH TABLES';
|
WHERE state= 'Waiting for table metadata lock' AND info= 'FLUSH TABLES m1';
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
SET DEBUG_SYNC= 'now SIGNAL dropped';
|
||||||
|
|
||||||
|
@ -175,6 +175,7 @@ c1
|
|||||||
connect flush,localhost,root,,;
|
connect flush,localhost,root,,;
|
||||||
connection flush;
|
connection flush;
|
||||||
flush tables;
|
flush tables;
|
||||||
|
flush table t1;
|
||||||
connect waiter,localhost,root,,;
|
connect waiter,localhost,root,,;
|
||||||
connection waiter;
|
connection waiter;
|
||||||
connection default;
|
connection default;
|
||||||
@ -258,10 +259,11 @@ a b
|
|||||||
flush tables;
|
flush tables;
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
a b
|
a b
|
||||||
0 a
|
2 c
|
||||||
|
flush tables t1;
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
a b
|
a b
|
||||||
1 b
|
0 a
|
||||||
flush tables with read lock;
|
flush tables with read lock;
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
a b
|
a b
|
||||||
|
@ -179,12 +179,13 @@ handler t1 open;
|
|||||||
handler t1 read first;
|
handler t1 read first;
|
||||||
connect (flush,localhost,root,,);
|
connect (flush,localhost,root,,);
|
||||||
connection flush;
|
connection flush;
|
||||||
send flush tables;
|
flush tables;
|
||||||
|
send flush table t1;
|
||||||
connect (waiter,localhost,root,,);
|
connect (waiter,localhost,root,,);
|
||||||
connection waiter;
|
connection waiter;
|
||||||
let $wait_condition=
|
let $wait_condition=
|
||||||
select count(*) = 1 from information_schema.processlist
|
select count(*) = 1 from information_schema.processlist
|
||||||
where state = "Waiting for table flush";
|
where state = "Waiting for table metadata lock";
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
connection default;
|
connection default;
|
||||||
handler t2 open;
|
handler t2 open;
|
||||||
@ -282,6 +283,7 @@ handler t1 read a first;
|
|||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
flush tables;
|
flush tables;
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
|
flush tables t1;
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
flush tables with read lock;
|
flush tables with read lock;
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
|
@ -3,6 +3,7 @@ LOCK TABLE t1 WRITE;
|
|||||||
connect con1,localhost,root,,test;
|
connect con1,localhost,root,,test;
|
||||||
SET lock_wait_timeout= 2;
|
SET lock_wait_timeout= 2;
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
|
FLUSH TABLES t1;
|
||||||
connection default;
|
connection default;
|
||||||
CALL non_existing_sp;
|
CALL non_existing_sp;
|
||||||
ERROR 42000: PROCEDURE test.non_existing_sp does not exist
|
ERROR 42000: PROCEDURE test.non_existing_sp does not exist
|
||||||
|
@ -12,8 +12,8 @@ LOCK TABLE t1 WRITE;
|
|||||||
|
|
||||||
--connect (con1,localhost,root,,test)
|
--connect (con1,localhost,root,,test)
|
||||||
SET lock_wait_timeout= 2;
|
SET lock_wait_timeout= 2;
|
||||||
--send
|
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
|
--send FLUSH TABLES t1
|
||||||
--connection default
|
--connection default
|
||||||
--error ER_SP_DOES_NOT_EXIST
|
--error ER_SP_DOES_NOT_EXIST
|
||||||
CALL non_existing_sp;
|
CALL non_existing_sp;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
-- source include/master-slave.inc
|
-- source include/master-slave.inc
|
||||||
|
|
||||||
eval create table t1 (a int) engine=$engine_type;
|
eval create table t1 (a int) engine=$engine_type;
|
||||||
flush tables;
|
flush tables t1;
|
||||||
let $MYSQLD_DATADIR= `select @@datadir`;
|
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||||
remove_file $MYSQLD_DATADIR/test/t1.MYI ;
|
remove_file $MYSQLD_DATADIR/test/t1.MYI ;
|
||||||
drop table if exists t1;
|
drop table if exists t1;
|
||||||
|
@ -147,7 +147,7 @@ let $start_pos= `select @binlog_start_pos`;
|
|||||||
connection master;
|
connection master;
|
||||||
SET SESSION binlog_annotate_row_events = ON;
|
SET SESSION binlog_annotate_row_events = ON;
|
||||||
INSERT DELAYED INTO test1.t4 VALUES (1,1);
|
INSERT DELAYED INTO test1.t4 VALUES (1,1);
|
||||||
FLUSH TABLES;
|
FLUSH TABLES test1.t4;
|
||||||
SELECT * FROM test1.t4 ORDER BY a;
|
SELECT * FROM test1.t4 ORDER BY a;
|
||||||
|
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
|
@ -10,7 +10,7 @@ eval create table t1(a int not null primary key) engine=$engine_type;
|
|||||||
insert delayed into t1 values (1);
|
insert delayed into t1 values (1);
|
||||||
insert delayed into t1 values (2);
|
insert delayed into t1 values (2);
|
||||||
insert delayed into t1 values (3);
|
insert delayed into t1 values (3);
|
||||||
flush tables;
|
flush tables t1;
|
||||||
SELECT * FROM t1 ORDER BY a;
|
SELECT * FROM t1 ORDER BY a;
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
include/master-slave.inc
|
include/master-slave.inc
|
||||||
[connection master]
|
[connection master]
|
||||||
create table t1 (a int) engine=myisam;
|
create table t1 (a int) engine=myisam;
|
||||||
flush tables;
|
flush tables t1;
|
||||||
drop table if exists t1;
|
drop table if exists t1;
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1017 Can't find file: './test/t1.MYI' (errno: 2 "No such file or directory")
|
Warning 1017 Can't find file: './test/t1.MYI' (errno: 2 "No such file or directory")
|
||||||
|
@ -180,7 +180,7 @@ slave-bin.000001 # Rotate 2 # slave-bin.000002;pos=4
|
|||||||
connection master;
|
connection master;
|
||||||
SET SESSION binlog_annotate_row_events = ON;
|
SET SESSION binlog_annotate_row_events = ON;
|
||||||
INSERT DELAYED INTO test1.t4 VALUES (1,1);
|
INSERT DELAYED INTO test1.t4 VALUES (1,1);
|
||||||
FLUSH TABLES;
|
FLUSH TABLES test1.t4;
|
||||||
SELECT * FROM test1.t4 ORDER BY a;
|
SELECT * FROM test1.t4 ORDER BY a;
|
||||||
a b
|
a b
|
||||||
1 1
|
1 1
|
||||||
|
@ -160,7 +160,7 @@ slave-bin.000001 # Rotate 2 # slave-bin.000002;pos=4
|
|||||||
connection master;
|
connection master;
|
||||||
SET SESSION binlog_annotate_row_events = ON;
|
SET SESSION binlog_annotate_row_events = ON;
|
||||||
INSERT DELAYED INTO test1.t4 VALUES (1,1);
|
INSERT DELAYED INTO test1.t4 VALUES (1,1);
|
||||||
FLUSH TABLES;
|
FLUSH TABLES test1.t4;
|
||||||
SELECT * FROM test1.t4 ORDER BY a;
|
SELECT * FROM test1.t4 ORDER BY a;
|
||||||
a b
|
a b
|
||||||
1 1
|
1 1
|
||||||
|
@ -5,7 +5,7 @@ create table t1(a int not null primary key) engine=myisam;
|
|||||||
insert delayed into t1 values (1);
|
insert delayed into t1 values (1);
|
||||||
insert delayed into t1 values (2);
|
insert delayed into t1 values (2);
|
||||||
insert delayed into t1 values (3);
|
insert delayed into t1 values (3);
|
||||||
flush tables;
|
flush tables t1;
|
||||||
SELECT * FROM t1 ORDER BY a;
|
SELECT * FROM t1 ORDER BY a;
|
||||||
a
|
a
|
||||||
1
|
1
|
||||||
|
@ -122,7 +122,7 @@ select * from t;
|
|||||||
a b c d e
|
a b c d e
|
||||||
10 5 5 5 5
|
10 5 5 5 5
|
||||||
replace delayed t (a,b,d) values (10,6,6);
|
replace delayed t (a,b,d) values (10,6,6);
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t;
|
check table t;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t check status OK
|
test.t check status OK
|
||||||
@ -130,7 +130,7 @@ select * from t;
|
|||||||
a b c d e
|
a b c d e
|
||||||
10 6 6 6 6
|
10 6 6 6 6
|
||||||
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t;
|
check table t;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t check status OK
|
test.t check status OK
|
||||||
|
@ -124,7 +124,7 @@ select * from t;
|
|||||||
a b c d e
|
a b c d e
|
||||||
10 5 5 5 5
|
10 5 5 5 5
|
||||||
replace delayed t (a,b,d) values (10,6,6);
|
replace delayed t (a,b,d) values (10,6,6);
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t;
|
check table t;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t check status OK
|
test.t check status OK
|
||||||
@ -132,7 +132,7 @@ select * from t;
|
|||||||
a b c d e
|
a b c d e
|
||||||
10 6 6 6 6
|
10 6 6 6 6
|
||||||
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t;
|
check table t;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t check status OK
|
test.t check status OK
|
||||||
@ -304,7 +304,7 @@ select * from t;
|
|||||||
a b c d e
|
a b c d e
|
||||||
10 5 5 5 5
|
10 5 5 5 5
|
||||||
replace delayed t (a,b,d) values (10,6,6);
|
replace delayed t (a,b,d) values (10,6,6);
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t;
|
check table t;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t check status OK
|
test.t check status OK
|
||||||
@ -312,7 +312,7 @@ select * from t;
|
|||||||
a b c d e
|
a b c d e
|
||||||
10 6 6 6 6
|
10 6 6 6 6
|
||||||
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t;
|
check table t;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t check status OK
|
test.t check status OK
|
||||||
|
@ -182,16 +182,36 @@ a b c
|
|||||||
2 3 y
|
2 3 y
|
||||||
0 1 y,n
|
0 1 y,n
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
CREATE TABLE t1 (
|
SET @old_debug= @@global.debug;
|
||||||
|
SET @old_debug= @@global.debug;
|
||||||
|
SET GLOBAL debug_dbug= "+d,write_delay_wakeup";
|
||||||
|
CREATE TABLE t1 (a int,
|
||||||
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
tsv TIMESTAMP AS (ADDDATE(ts, INTERVAL 1 DAY)) VIRTUAL
|
tsv TIMESTAMP AS (ADDDATE(ts, INTERVAL 1 DAY)) VIRTUAL
|
||||||
) ENGINE=MyISAM;
|
) ENGINE=MyISAM;
|
||||||
INSERT INTO t1 (tsv) VALUES (DEFAULT);
|
# First test FLUSH TABLES
|
||||||
INSERT DELAYED INTO t1 (tsv) VALUES (DEFAULT);
|
INSERT INTO t1 (a,tsv) VALUES (1,DEFAULT);
|
||||||
|
INSERT DELAYED INTO t1 (a,tsv) VALUES (2,DEFAULT);
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
|
SELECT COUNT(*) > 0 FROM t1;
|
||||||
|
COUNT(*) > 0
|
||||||
|
1
|
||||||
|
# Then test FLUSH TABLES t1;
|
||||||
|
INSERT INTO t1 (a,tsv) VALUES (3,DEFAULT);
|
||||||
|
INSERT DELAYED INTO t1 (a,tsv) VALUES (4,DEFAULT);
|
||||||
|
FLUSH TABLES t1;
|
||||||
SELECT COUNT(*) FROM t1;
|
SELECT COUNT(*) FROM t1;
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
2
|
4
|
||||||
|
# Then test FLUSH TABLES WITH READ LOCK;
|
||||||
|
INSERT INTO t1 (a,tsv) VALUES (5,DEFAULT);
|
||||||
|
INSERT DELAYED INTO t1 (a,tsv) VALUES (6,DEFAULT);
|
||||||
|
FLUSH TABLES WITH READ LOCK;
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
COUNT(*)
|
||||||
|
6
|
||||||
|
set GLOBAL debug_dbug= @old_debug;
|
||||||
|
unlock tables;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
# MDEV-4823 Server crashes in Item_func_not::fix_fields on
|
# MDEV-4823 Server crashes in Item_func_not::fix_fields on
|
||||||
|
@ -93,10 +93,10 @@ check table t; select * from t;
|
|||||||
insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
|
insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
|
||||||
check table t; select * from t;
|
check table t; select * from t;
|
||||||
replace delayed t (a,b,d) values (10,6,6);
|
replace delayed t (a,b,d) values (10,6,6);
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t; select * from t;
|
check table t; select * from t;
|
||||||
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
|
||||||
flush tables;
|
flush tables t;
|
||||||
check table t; select * from t;
|
check table t; select * from t;
|
||||||
--write_file $MYSQLTEST_VARDIR/tmp/vblobs.txt
|
--write_file $MYSQLTEST_VARDIR/tmp/vblobs.txt
|
||||||
10 8 foo 8 foo
|
10 8 foo 8 foo
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
--source include/have_ucs2.inc
|
--source include/have_ucs2.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
|
|
||||||
let $MYSQLD_DATADIR= `select @@datadir`;
|
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||||
|
|
||||||
@ -184,19 +185,35 @@ drop table t1,t2;
|
|||||||
# Bug mdev-3938: INSERT DELAYED for a table with virtual columns
|
# Bug mdev-3938: INSERT DELAYED for a table with virtual columns
|
||||||
#
|
#
|
||||||
|
|
||||||
CREATE TABLE t1 (
|
SET @old_debug= @@global.debug;
|
||||||
|
SET @old_debug= @@global.debug;
|
||||||
|
SET GLOBAL debug_dbug= "+d,write_delay_wakeup";
|
||||||
|
CREATE TABLE t1 (a int,
|
||||||
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
tsv TIMESTAMP AS (ADDDATE(ts, INTERVAL 1 DAY)) VIRTUAL
|
tsv TIMESTAMP AS (ADDDATE(ts, INTERVAL 1 DAY)) VIRTUAL
|
||||||
) ENGINE=MyISAM;
|
) ENGINE=MyISAM;
|
||||||
|
|
||||||
INSERT INTO t1 (tsv) VALUES (DEFAULT);
|
--echo # First test FLUSH TABLES
|
||||||
|
INSERT INTO t1 (a,tsv) VALUES (1,DEFAULT);
|
||||||
INSERT DELAYED INTO t1 (tsv) VALUES (DEFAULT);
|
INSERT DELAYED INTO t1 (a,tsv) VALUES (2,DEFAULT);
|
||||||
|
|
||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
|
# Count may be 1 or 2, depending on FLUSH happened before or after delayed
|
||||||
|
SELECT COUNT(*) > 0 FROM t1;
|
||||||
|
|
||||||
|
--echo # Then test FLUSH TABLES t1;
|
||||||
|
INSERT INTO t1 (a,tsv) VALUES (3,DEFAULT);
|
||||||
|
INSERT DELAYED INTO t1 (a,tsv) VALUES (4,DEFAULT);
|
||||||
|
FLUSH TABLES t1;
|
||||||
SELECT COUNT(*) FROM t1;
|
SELECT COUNT(*) FROM t1;
|
||||||
|
|
||||||
|
--echo # Then test FLUSH TABLES WITH READ LOCK;
|
||||||
|
|
||||||
|
INSERT INTO t1 (a,tsv) VALUES (5,DEFAULT);
|
||||||
|
INSERT DELAYED INTO t1 (a,tsv) VALUES (6,DEFAULT);
|
||||||
|
FLUSH TABLES WITH READ LOCK;
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
set GLOBAL debug_dbug= @old_debug;
|
||||||
|
unlock tables;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -1862,11 +1862,8 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
|
|||||||
MDL_ticket *ticket;
|
MDL_ticket *ticket;
|
||||||
enum_mdl_duration found_duration;
|
enum_mdl_duration found_duration;
|
||||||
|
|
||||||
DBUG_ASSERT(mdl_request->type != MDL_EXCLUSIVE ||
|
|
||||||
is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE));
|
|
||||||
DBUG_ASSERT(mdl_request->ticket == NULL);
|
|
||||||
|
|
||||||
/* Don't take chances in production. */
|
/* Don't take chances in production. */
|
||||||
|
DBUG_ASSERT(mdl_request->ticket == NULL);
|
||||||
mdl_request->ticket= NULL;
|
mdl_request->ticket= NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
195
sql/sql_base.cc
195
sql/sql_base.cc
@ -306,49 +306,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Close all tables which aren't in use by any thread
|
|
||||||
|
|
||||||
@param thd Thread context
|
|
||||||
@param tables List of tables to remove from the cache
|
|
||||||
@param wait_for_refresh Wait for a impending flush
|
|
||||||
@param timeout Timeout for waiting for flush to be completed.
|
|
||||||
|
|
||||||
@note THD can be NULL, but then wait_for_refresh must be FALSE
|
|
||||||
and tables must be NULL.
|
|
||||||
|
|
||||||
@note When called as part of FLUSH TABLES WITH READ LOCK this function
|
|
||||||
ignores metadata locks held by other threads. In order to avoid
|
|
||||||
situation when FLUSH TABLES WITH READ LOCK sneaks in at the moment
|
|
||||||
when some write-locked table is being reopened (by FLUSH TABLES or
|
|
||||||
ALTER TABLE) we have to rely on additional global shared metadata
|
|
||||||
lock taken by thread trying to obtain global read lock.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
struct close_cached_tables_arg
|
|
||||||
{
|
|
||||||
tdc_version_t refresh_version;
|
|
||||||
TDC_element *element;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static my_bool close_cached_tables_callback(TDC_element *element,
|
|
||||||
close_cached_tables_arg *arg)
|
|
||||||
{
|
|
||||||
mysql_mutex_lock(&element->LOCK_table_share);
|
|
||||||
if (element->share && element->flushed &&
|
|
||||||
element->version < arg->refresh_version)
|
|
||||||
{
|
|
||||||
/* wait_for_old_version() will unlock mutex and free share */
|
|
||||||
arg->element= element;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Close all tables that are not in use in table definition cache
|
Close all tables that are not in use in table definition cache
|
||||||
|
|
||||||
@ -377,38 +334,37 @@ void purge_tables(bool purge_flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
close_cached_tables
|
||||||
|
|
||||||
|
This function has two separate usages:
|
||||||
|
1) Close not used tables in the table cache to free memory
|
||||||
|
2) Close a list of tables and wait until they are not used anymore. This
|
||||||
|
is used mainly when preparing a table for export.
|
||||||
|
|
||||||
|
If there are locked tables, they are closed and reopened before
|
||||||
|
function returns. This is done to ensure that table files will be closed
|
||||||
|
by all threads and thus external copyable when FLUSH TABLES returns.
|
||||||
|
*/
|
||||||
|
|
||||||
bool close_cached_tables(THD *thd, TABLE_LIST *tables,
|
bool close_cached_tables(THD *thd, TABLE_LIST *tables,
|
||||||
bool wait_for_refresh, ulong timeout)
|
bool wait_for_refresh, ulong timeout)
|
||||||
{
|
{
|
||||||
bool result= FALSE;
|
|
||||||
struct timespec abstime;
|
|
||||||
tdc_version_t refresh_version;
|
|
||||||
DBUG_ENTER("close_cached_tables");
|
DBUG_ENTER("close_cached_tables");
|
||||||
DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
|
DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
|
||||||
|
DBUG_ASSERT(wait_for_refresh || !tables);
|
||||||
refresh_version= tdc_increment_refresh_version();
|
|
||||||
|
|
||||||
if (!tables)
|
if (!tables)
|
||||||
purge_tables(true);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
bool found=0;
|
/* Free tables that are not used */
|
||||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
purge_tables(false);
|
||||||
{
|
if (!wait_for_refresh)
|
||||||
/* tdc_remove_table() also sets TABLE_SHARE::version to 0. */
|
DBUG_RETURN(false);
|
||||||
found|= tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, table->db.str,
|
|
||||||
table->table_name.str, TRUE);
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
wait_for_refresh=0; // Nothing to wait for
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_PRINT("info", ("open table definitions: %d",
|
DBUG_PRINT("info", ("open table definitions: %d",
|
||||||
(int) tdc_records()));
|
(int) tdc_records()));
|
||||||
|
|
||||||
if (!wait_for_refresh)
|
|
||||||
DBUG_RETURN(result);
|
|
||||||
|
|
||||||
if (thd->locked_tables_mode)
|
if (thd->locked_tables_mode)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -419,8 +375,9 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
|
|||||||
*/
|
*/
|
||||||
TABLE_LIST *tables_to_reopen= (tables ? tables :
|
TABLE_LIST *tables_to_reopen= (tables ? tables :
|
||||||
thd->locked_tables_list.locked_tables());
|
thd->locked_tables_list.locked_tables());
|
||||||
|
bool result= false;
|
||||||
|
|
||||||
/* Close open HANDLER instances to avoid self-deadlock. */
|
/* close open HANDLER for this thread to allow table to be closed */
|
||||||
mysql_ha_flush_tables(thd, tables_to_reopen);
|
mysql_ha_flush_tables(thd, tables_to_reopen);
|
||||||
|
|
||||||
for (TABLE_LIST *table_list= tables_to_reopen; table_list;
|
for (TABLE_LIST *table_list= tables_to_reopen; table_list;
|
||||||
@ -435,64 +392,15 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
|
|||||||
if (! table)
|
if (! table)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (wait_while_table_is_used(thd, table,
|
if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE,
|
||||||
HA_EXTRA_PREPARE_FOR_FORCED_CLOSE))
|
timeout))
|
||||||
{
|
{
|
||||||
result= TRUE;
|
result= true;
|
||||||
goto err_with_reopen;
|
break;
|
||||||
}
|
}
|
||||||
|
table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
|
||||||
close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
|
close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait until all threads have closed all the tables we are flushing. */
|
|
||||||
DBUG_PRINT("info", ("Waiting for other threads to close their open tables"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
To a self-deadlock or deadlocks with other FLUSH threads
|
|
||||||
waiting on our open HANDLERs, we have to flush them.
|
|
||||||
*/
|
|
||||||
mysql_ha_flush(thd);
|
|
||||||
DEBUG_SYNC(thd, "after_flush_unlock");
|
|
||||||
|
|
||||||
if (!tables)
|
|
||||||
{
|
|
||||||
int r= 0;
|
|
||||||
close_cached_tables_arg argument;
|
|
||||||
argument.refresh_version= refresh_version;
|
|
||||||
set_timespec(abstime, timeout);
|
|
||||||
|
|
||||||
while (!thd->killed &&
|
|
||||||
(r= tdc_iterate(thd,
|
|
||||||
(my_hash_walk_action) close_cached_tables_callback,
|
|
||||||
&argument)) == 1 &&
|
|
||||||
!argument.element->share->wait_for_old_version(thd, &abstime,
|
|
||||||
MDL_wait_for_subgraph::DEADLOCK_WEIGHT_DDL))
|
|
||||||
/* no-op */;
|
|
||||||
|
|
||||||
if (r)
|
|
||||||
result= TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
|
||||||
{
|
|
||||||
if (thd->killed)
|
|
||||||
break;
|
|
||||||
if (tdc_wait_for_old_version(thd, table->db.str, table->table_name.str,
|
|
||||||
timeout,
|
|
||||||
MDL_wait_for_subgraph::DEADLOCK_WEIGHT_DDL,
|
|
||||||
refresh_version))
|
|
||||||
{
|
|
||||||
result= TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err_with_reopen:
|
|
||||||
if (thd->locked_tables_mode)
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
No other thread has the locked tables open; reopen them and get the
|
No other thread has the locked tables open; reopen them and get the
|
||||||
old locks. This should always succeed (unless some external process
|
old locks. This should always succeed (unless some external process
|
||||||
@ -508,9 +416,41 @@ err_with_reopen:
|
|||||||
*/
|
*/
|
||||||
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
|
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
|
||||||
tab->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
tab->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
||||||
}
|
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
}
|
}
|
||||||
|
else if (tables)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Get an explicit MDL lock for all requested tables to ensure they are
|
||||||
|
not used by any other thread
|
||||||
|
*/
|
||||||
|
MDL_request_list mdl_requests;
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("Waiting for other threads to close their open tables"));
|
||||||
|
DEBUG_SYNC(thd, "after_flush_unlock");
|
||||||
|
|
||||||
|
/* close open HANDLER for this thread to allow table to be closed */
|
||||||
|
mysql_ha_flush_tables(thd, tables);
|
||||||
|
|
||||||
|
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||||
|
{
|
||||||
|
MDL_request *mdl_request= new (thd->mem_root) MDL_request;
|
||||||
|
if (mdl_request == NULL)
|
||||||
|
DBUG_RETURN(true);
|
||||||
|
mdl_request->init(&table->mdl_request.key, MDL_EXCLUSIVE, MDL_STATEMENT);
|
||||||
|
mdl_requests.push_front(mdl_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thd->mdl_context.acquire_locks(&mdl_requests, timeout))
|
||||||
|
DBUG_RETURN(true);
|
||||||
|
|
||||||
|
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||||
|
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db.str,
|
||||||
|
table->table_name.str, false);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -688,8 +628,17 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Close cached connections
|
||||||
|
|
||||||
|
@return false ok
|
||||||
|
@return true If there was an error from closed_cached_connection_tables or
|
||||||
|
if there was any open connections that we had to force closed
|
||||||
|
*/
|
||||||
|
|
||||||
bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
|
bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
|
||||||
{
|
{
|
||||||
|
bool res= false;
|
||||||
close_cached_connection_tables_arg argument;
|
close_cached_connection_tables_arg argument;
|
||||||
DBUG_ENTER("close_cached_connections");
|
DBUG_ENTER("close_cached_connections");
|
||||||
DBUG_ASSERT(thd);
|
DBUG_ASSERT(thd);
|
||||||
@ -703,9 +652,13 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
|
|||||||
&argument))
|
&argument))
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(true);
|
||||||
|
|
||||||
DBUG_RETURN(argument.tables ?
|
for (TABLE_LIST *table= argument.tables; table; table= table->next_local)
|
||||||
close_cached_tables(thd, argument.tables, FALSE, LONG_TIMEOUT) :
|
res|= tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
||||||
false);
|
table->db.str,
|
||||||
|
table->table_name.str, TRUE);
|
||||||
|
|
||||||
|
/* Return true if we found any open connections */
|
||||||
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -329,15 +329,10 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
if (thd && thd->wsrep_applier)
|
/* In case of applier thread, do not call flush tables */
|
||||||
|
if (!thd || !thd->wsrep_applier)
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
In case of applier thread, do not wait for table share(s) to be
|
|
||||||
removed from table definition cache.
|
|
||||||
*/
|
|
||||||
options|= REFRESH_FAST;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (close_cached_tables(thd, tables,
|
if (close_cached_tables(thd, tables,
|
||||||
((options & REFRESH_FAST) ? FALSE : TRUE),
|
((options & REFRESH_FAST) ? FALSE : TRUE),
|
||||||
(thd ? thd->variables.lock_wait_timeout :
|
(thd ? thd->variables.lock_wait_timeout :
|
||||||
@ -350,6 +345,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
|
|||||||
result= 1;
|
result= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
my_dbopt_cleanup();
|
my_dbopt_cleanup();
|
||||||
}
|
}
|
||||||
if (options & REFRESH_HOSTS)
|
if (options & REFRESH_HOSTS)
|
||||||
|
@ -1094,6 +1094,7 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
|||||||
TABLE *table;
|
TABLE *table;
|
||||||
TDC_element *element;
|
TDC_element *element;
|
||||||
uint my_refs= 1;
|
uint my_refs= 1;
|
||||||
|
bool res= false;
|
||||||
DBUG_ENTER("tdc_remove_table");
|
DBUG_ENTER("tdc_remove_table");
|
||||||
DBUG_PRINT("enter",("name: %s remove_type: %d", table_name, remove_type));
|
DBUG_PRINT("enter",("name: %s remove_type: %d", table_name, remove_type));
|
||||||
|
|
||||||
@ -1101,7 +1102,6 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
|||||||
thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
|
thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
|
||||||
MDL_EXCLUSIVE));
|
MDL_EXCLUSIVE));
|
||||||
|
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_unused_shares);
|
mysql_mutex_lock(&LOCK_unused_shares);
|
||||||
if (!(element= tdc_lock_share(thd, db, table_name)))
|
if (!(element= tdc_lock_share(thd, db, table_name)))
|
||||||
{
|
{
|
||||||
@ -1123,7 +1123,7 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
|||||||
mysql_mutex_unlock(&LOCK_unused_shares);
|
mysql_mutex_unlock(&LOCK_unused_shares);
|
||||||
|
|
||||||
tdc_delete_share_from_hash(element);
|
tdc_delete_share_from_hash(element);
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(false);
|
||||||
}
|
}
|
||||||
mysql_mutex_unlock(&LOCK_unused_shares);
|
mysql_mutex_unlock(&LOCK_unused_shares);
|
||||||
|
|
||||||
@ -1189,10 +1189,16 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
|||||||
#endif
|
#endif
|
||||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mysql_mutex_lock(&element->LOCK_table_share);
|
||||||
|
res= element->ref_count > 1;
|
||||||
|
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||||
|
}
|
||||||
|
|
||||||
tdc_release_share(element->share);
|
tdc_release_share(element->share);
|
||||||
|
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user