mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Let "FTWRL <table_list>" use extra(HA_EXTRA_FLUSH)
Rather than flushing caches with tdc_remove_table(TDC_RT_REMOVE_UNUSED) flush them with extra(HA_EXTRA_FLUSH) instead. This goes inline with regular FTWRL. Part of MDEV-17882 - Cleanup refresh version
This commit is contained in:
@ -329,12 +329,9 @@ flush tables t1 with read lock;
|
|||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
||||||
unlock tables;
|
unlock tables;
|
||||||
#
|
|
||||||
# Sic: lost handler position.
|
|
||||||
#
|
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
a
|
a
|
||||||
1
|
3
|
||||||
handler t1 close;
|
handler t1 close;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
#
|
#
|
||||||
|
@ -412,9 +412,6 @@ flush tables t1 with read lock;
|
|||||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
unlock tables;
|
unlock tables;
|
||||||
--echo #
|
|
||||||
--echo # Sic: lost handler position.
|
|
||||||
--echo #
|
|
||||||
handler t1 read a next;
|
handler t1 read a next;
|
||||||
handler t1 close;
|
handler t1 close;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@ -2010,117 +2010,6 @@ connection deadlock_con1;
|
|||||||
connection default;
|
connection default;
|
||||||
# Reaping ALTER. It should succeed and not produce ER_LOCK_DEADLOCK.
|
# Reaping ALTER. It should succeed and not produce ER_LOCK_DEADLOCK.
|
||||||
drop table t1;
|
drop table t1;
|
||||||
#
|
|
||||||
# Now, test for a situation in which deadlock involves waiting not
|
|
||||||
# only in MDL subsystem but also for TDC. Such deadlocks should be
|
|
||||||
# successfully detected. If possible, they should be resolved without
|
|
||||||
# resorting to ER_LOCK_DEADLOCK error.
|
|
||||||
#
|
|
||||||
create table t1(i int);
|
|
||||||
create table t2(j int);
|
|
||||||
#
|
|
||||||
# First, let us check how we handle a simple scenario involving
|
|
||||||
# waits in MDL and TDC.
|
|
||||||
#
|
|
||||||
set debug_sync= 'RESET';
|
|
||||||
connection deadlock_con1;
|
|
||||||
# Start a statement, which will acquire SR metadata lock on t1, open it
|
|
||||||
# and then stop, before trying to acquire SW lock on t2 and opening it.
|
|
||||||
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
|
|
||||||
# Sending:
|
|
||||||
select * from t1 where i in (select j from t2 for update);
|
|
||||||
connection deadlock_con2;
|
|
||||||
# Wait till the above SELECT stops.
|
|
||||||
set debug_sync='now WAIT_FOR parked';
|
|
||||||
# The below FLUSH TABLES WITH READ LOCK should acquire
|
|
||||||
# SNW locks on t1 and t2 and wait till SELECT closes t1.
|
|
||||||
# Sending:
|
|
||||||
flush tables t1, t2 with read lock;
|
|
||||||
connection deadlock_con3;
|
|
||||||
# Wait until FLUSH TABLES WITH t1, t2 READ LOCK starts waiting
|
|
||||||
# for SELECT to close t1.
|
|
||||||
# Resume SELECT, so it tries to acquire SW lock on t1 and blocks,
|
|
||||||
# creating a deadlock. This deadlock should be detected and resolved
|
|
||||||
# by backing-off SELECT. As a result FTWRL should be able to finish.
|
|
||||||
set debug_sync='now SIGNAL go';
|
|
||||||
connection deadlock_con2;
|
|
||||||
# Reap FLUSH TABLES WITH READ LOCK.
|
|
||||||
unlock tables;
|
|
||||||
connection deadlock_con1;
|
|
||||||
# Reap SELECT.
|
|
||||||
i
|
|
||||||
#
|
|
||||||
# The same scenario with a slightly different order of events
|
|
||||||
# which emphasizes that setting correct deadlock detector weights
|
|
||||||
# for flush waits is important.
|
|
||||||
#
|
|
||||||
set debug_sync= 'RESET';
|
|
||||||
connection deadlock_con2;
|
|
||||||
set debug_sync='flush_tables_with_read_lock_after_acquire_locks SIGNAL parked WAIT_FOR go';
|
|
||||||
# The below FLUSH TABLES WITH READ LOCK should acquire
|
|
||||||
# SNW locks on t1 and t2 and wait on debug sync point.
|
|
||||||
# Sending:
|
|
||||||
flush tables t1, t2 with read lock;
|
|
||||||
connection deadlock_con1;
|
|
||||||
# Wait till FLUSH TABLE WITH READ LOCK stops.
|
|
||||||
set debug_sync='now WAIT_FOR parked';
|
|
||||||
# Start statement which will acquire SR metadata lock on t1, open
|
|
||||||
# it and then will block while trying to acquire SW lock on t2.
|
|
||||||
# Sending:
|
|
||||||
select * from t1 where i in (select j from t2 for update);
|
|
||||||
connection deadlock_con3;
|
|
||||||
# Wait till the above SELECT blocks.
|
|
||||||
# Resume FLUSH TABLES, so it tries to flush t1, thus creating
|
|
||||||
# a deadlock. This deadlock should be detected and resolved by
|
|
||||||
# backing-off SELECT. As a result FTWRL should be able to finish.
|
|
||||||
set debug_sync='now SIGNAL go';
|
|
||||||
connection deadlock_con2;
|
|
||||||
# Reap FLUSH TABLES WITH READ LOCK.
|
|
||||||
unlock tables;
|
|
||||||
connection deadlock_con1;
|
|
||||||
# Reap SELECT.
|
|
||||||
i
|
|
||||||
#
|
|
||||||
# Now a more complex scenario involving two connections
|
|
||||||
# waiting for MDL and one for TDC.
|
|
||||||
#
|
|
||||||
set debug_sync= 'RESET';
|
|
||||||
connection deadlock_con1;
|
|
||||||
# Start a statement which will acquire SR metadata lock on t2, open it
|
|
||||||
# and then stop, before trying to acquire SR on t1 and opening it.
|
|
||||||
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
|
|
||||||
# Sending:
|
|
||||||
select * from t2, t1;
|
|
||||||
connection deadlock_con2;
|
|
||||||
# Wait till the above SELECT stops.
|
|
||||||
set debug_sync='now WAIT_FOR parked';
|
|
||||||
# The below FLUSH TABLES WITH READ LOCK should acquire
|
|
||||||
# SNW locks on t2 and wait till SELECT closes t2.
|
|
||||||
# Sending:
|
|
||||||
flush tables t2 with read lock;
|
|
||||||
connection deadlock_con3;
|
|
||||||
# Wait until FLUSH TABLES WITH READ LOCK starts waiting
|
|
||||||
# for SELECT to close t2.
|
|
||||||
# The below DROP TABLES should acquire X lock on t1 and start
|
|
||||||
# waiting for X lock on t2.
|
|
||||||
# Sending:
|
|
||||||
drop tables t1, t2;
|
|
||||||
connection default;
|
|
||||||
# Wait until DROP TABLES starts waiting for X lock on t2.
|
|
||||||
# Resume SELECT, so it tries to acquire SR lock on t1 and blocks,
|
|
||||||
# creating a deadlock. This deadlock should be detected and resolved
|
|
||||||
# by backing-off SELECT. As a result, FTWRL should be able to finish.
|
|
||||||
set debug_sync='now SIGNAL go';
|
|
||||||
connection deadlock_con2;
|
|
||||||
# Reap FLUSH TABLES WITH READ LOCK.
|
|
||||||
# Unblock DROP TABLES.
|
|
||||||
unlock tables;
|
|
||||||
connection deadlock_con3;
|
|
||||||
# Reap DROP TABLES.
|
|
||||||
connection deadlock_con1;
|
|
||||||
# Reap SELECT. It should emit error about missing table.
|
|
||||||
ERROR 42S02: Table 'test.t2' doesn't exist
|
|
||||||
connection default;
|
|
||||||
set debug_sync= 'RESET';
|
set debug_sync= 'RESET';
|
||||||
disconnect deadlock_con1;
|
disconnect deadlock_con1;
|
||||||
disconnect deadlock_con2;
|
disconnect deadlock_con2;
|
||||||
|
@ -2493,170 +2493,6 @@ connection default;
|
|||||||
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # Now, test for a situation in which deadlock involves waiting not
|
|
||||||
--echo # only in MDL subsystem but also for TDC. Such deadlocks should be
|
|
||||||
--echo # successfully detected. If possible, they should be resolved without
|
|
||||||
--echo # resorting to ER_LOCK_DEADLOCK error.
|
|
||||||
--echo #
|
|
||||||
create table t1(i int);
|
|
||||||
create table t2(j int);
|
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # First, let us check how we handle a simple scenario involving
|
|
||||||
--echo # waits in MDL and TDC.
|
|
||||||
--echo #
|
|
||||||
set debug_sync= 'RESET';
|
|
||||||
|
|
||||||
connection deadlock_con1;
|
|
||||||
--echo # Start a statement, which will acquire SR metadata lock on t1, open it
|
|
||||||
--echo # and then stop, before trying to acquire SW lock on t2 and opening it.
|
|
||||||
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
|
|
||||||
--echo # Sending:
|
|
||||||
--send select * from t1 where i in (select j from t2 for update)
|
|
||||||
|
|
||||||
connection deadlock_con2;
|
|
||||||
--echo # Wait till the above SELECT stops.
|
|
||||||
set debug_sync='now WAIT_FOR parked';
|
|
||||||
--echo # The below FLUSH TABLES WITH READ LOCK should acquire
|
|
||||||
--echo # SNW locks on t1 and t2 and wait till SELECT closes t1.
|
|
||||||
--echo # Sending:
|
|
||||||
send flush tables t1, t2 with read lock;
|
|
||||||
|
|
||||||
connection deadlock_con3;
|
|
||||||
--echo # Wait until FLUSH TABLES WITH t1, t2 READ LOCK starts waiting
|
|
||||||
--echo # for SELECT to close t1.
|
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table flush" and
|
|
||||||
info = "flush tables t1, t2 with read lock";
|
|
||||||
--source include/wait_condition.inc
|
|
||||||
|
|
||||||
--echo # Resume SELECT, so it tries to acquire SW lock on t1 and blocks,
|
|
||||||
--echo # creating a deadlock. This deadlock should be detected and resolved
|
|
||||||
--echo # by backing-off SELECT. As a result FTWRL should be able to finish.
|
|
||||||
set debug_sync='now SIGNAL go';
|
|
||||||
|
|
||||||
connection deadlock_con2;
|
|
||||||
--echo # Reap FLUSH TABLES WITH READ LOCK.
|
|
||||||
reap;
|
|
||||||
unlock tables;
|
|
||||||
|
|
||||||
connection deadlock_con1;
|
|
||||||
--echo # Reap SELECT.
|
|
||||||
reap;
|
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # The same scenario with a slightly different order of events
|
|
||||||
--echo # which emphasizes that setting correct deadlock detector weights
|
|
||||||
--echo # for flush waits is important.
|
|
||||||
--echo #
|
|
||||||
set debug_sync= 'RESET';
|
|
||||||
|
|
||||||
connection deadlock_con2;
|
|
||||||
set debug_sync='flush_tables_with_read_lock_after_acquire_locks SIGNAL parked WAIT_FOR go';
|
|
||||||
|
|
||||||
--echo # The below FLUSH TABLES WITH READ LOCK should acquire
|
|
||||||
--echo # SNW locks on t1 and t2 and wait on debug sync point.
|
|
||||||
--echo # Sending:
|
|
||||||
send flush tables t1, t2 with read lock;
|
|
||||||
|
|
||||||
connection deadlock_con1;
|
|
||||||
--echo # Wait till FLUSH TABLE WITH READ LOCK stops.
|
|
||||||
set debug_sync='now WAIT_FOR parked';
|
|
||||||
|
|
||||||
--echo # Start statement which will acquire SR metadata lock on t1, open
|
|
||||||
--echo # it and then will block while trying to acquire SW lock on t2.
|
|
||||||
--echo # Sending:
|
|
||||||
send select * from t1 where i in (select j from t2 for update);
|
|
||||||
|
|
||||||
connection deadlock_con3;
|
|
||||||
--echo # Wait till the above SELECT blocks.
|
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table metadata lock" and
|
|
||||||
info = "select * from t1 where i in (select j from t2 for update)";
|
|
||||||
--source include/wait_condition.inc
|
|
||||||
|
|
||||||
--echo # Resume FLUSH TABLES, so it tries to flush t1, thus creating
|
|
||||||
--echo # a deadlock. This deadlock should be detected and resolved by
|
|
||||||
--echo # backing-off SELECT. As a result FTWRL should be able to finish.
|
|
||||||
set debug_sync='now SIGNAL go';
|
|
||||||
|
|
||||||
connection deadlock_con2;
|
|
||||||
--echo # Reap FLUSH TABLES WITH READ LOCK.
|
|
||||||
reap;
|
|
||||||
unlock tables;
|
|
||||||
|
|
||||||
connection deadlock_con1;
|
|
||||||
--echo # Reap SELECT.
|
|
||||||
reap;
|
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # Now a more complex scenario involving two connections
|
|
||||||
--echo # waiting for MDL and one for TDC.
|
|
||||||
--echo #
|
|
||||||
set debug_sync= 'RESET';
|
|
||||||
|
|
||||||
connection deadlock_con1;
|
|
||||||
--echo # Start a statement which will acquire SR metadata lock on t2, open it
|
|
||||||
--echo # and then stop, before trying to acquire SR on t1 and opening it.
|
|
||||||
set debug_sync='open_tables_after_open_and_process_table SIGNAL parked WAIT_FOR go';
|
|
||||||
--echo # Sending:
|
|
||||||
send select * from t2, t1;
|
|
||||||
|
|
||||||
connection deadlock_con2;
|
|
||||||
--echo # Wait till the above SELECT stops.
|
|
||||||
set debug_sync='now WAIT_FOR parked';
|
|
||||||
--echo # The below FLUSH TABLES WITH READ LOCK should acquire
|
|
||||||
--echo # SNW locks on t2 and wait till SELECT closes t2.
|
|
||||||
--echo # Sending:
|
|
||||||
send flush tables t2 with read lock;
|
|
||||||
|
|
||||||
connection deadlock_con3;
|
|
||||||
--echo # Wait until FLUSH TABLES WITH READ LOCK starts waiting
|
|
||||||
--echo # for SELECT to close t2.
|
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table flush" and
|
|
||||||
info = "flush tables t2 with read lock";
|
|
||||||
--source include/wait_condition.inc
|
|
||||||
|
|
||||||
--echo # The below DROP TABLES should acquire X lock on t1 and start
|
|
||||||
--echo # waiting for X lock on t2.
|
|
||||||
--echo # Sending:
|
|
||||||
send drop tables t1, t2;
|
|
||||||
|
|
||||||
connection default;
|
|
||||||
--echo # Wait until DROP TABLES starts waiting for X lock on t2.
|
|
||||||
let $wait_condition=
|
|
||||||
select count(*) = 1 from information_schema.processlist
|
|
||||||
where state = "Waiting for table metadata lock" and
|
|
||||||
info = "drop tables t1, t2";
|
|
||||||
--source include/wait_condition.inc
|
|
||||||
|
|
||||||
--echo # Resume SELECT, so it tries to acquire SR lock on t1 and blocks,
|
|
||||||
--echo # creating a deadlock. This deadlock should be detected and resolved
|
|
||||||
--echo # by backing-off SELECT. As a result, FTWRL should be able to finish.
|
|
||||||
set debug_sync='now SIGNAL go';
|
|
||||||
|
|
||||||
connection deadlock_con2;
|
|
||||||
--echo # Reap FLUSH TABLES WITH READ LOCK.
|
|
||||||
reap;
|
|
||||||
--echo # Unblock DROP TABLES.
|
|
||||||
unlock tables;
|
|
||||||
|
|
||||||
connection deadlock_con3;
|
|
||||||
--echo # Reap DROP TABLES.
|
|
||||||
reap;
|
|
||||||
|
|
||||||
connection deadlock_con1;
|
|
||||||
--echo # Reap SELECT. It should emit error about missing table.
|
|
||||||
--error ER_NO_SUCH_TABLE
|
|
||||||
reap;
|
|
||||||
|
|
||||||
connection default;
|
|
||||||
|
|
||||||
set debug_sync= 'RESET';
|
set debug_sync= 'RESET';
|
||||||
|
|
||||||
disconnect deadlock_con1;
|
disconnect deadlock_con1;
|
||||||
|
@ -512,7 +512,6 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
|
|||||||
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
||||||
{
|
{
|
||||||
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
||||||
TABLE_LIST *table_list;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is called from SQLCOM_FLUSH, the transaction has
|
This is called from SQLCOM_FLUSH, the transaction has
|
||||||
@ -545,16 +544,10 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
|||||||
|
|
||||||
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
|
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
|
||||||
|
|
||||||
for (table_list= all_tables; table_list;
|
/* Reset ticket to satisfy asserts in open_tables(). */
|
||||||
|
for (auto table_list= all_tables; table_list;
|
||||||
table_list= table_list->next_global)
|
table_list= table_list->next_global)
|
||||||
{
|
|
||||||
/* Request removal of table from cache. */
|
|
||||||
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
|
||||||
table_list->db.str,
|
|
||||||
table_list->table_name.str);
|
|
||||||
/* Reset ticket to satisfy asserts in open_tables(). */
|
|
||||||
table_list->mdl_request.ticket= NULL;
|
table_list->mdl_request.ticket= NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->variables.option_bits|= OPTION_TABLE_LOCK;
|
thd->variables.option_bits|= OPTION_TABLE_LOCK;
|
||||||
@ -589,6 +582,16 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thd->lex->type & REFRESH_READ_LOCK)
|
||||||
|
{
|
||||||
|
for (auto table_list= all_tables; table_list;
|
||||||
|
table_list= table_list->next_global)
|
||||||
|
{
|
||||||
|
if (table_list->table->file->extra(HA_EXTRA_FLUSH))
|
||||||
|
goto error_reset_bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (thd->locked_tables_list.init_locked_tables(thd))
|
if (thd->locked_tables_list.init_locked_tables(thd))
|
||||||
goto error_reset_bits;
|
goto error_reset_bits;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user