mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +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;
|
||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
||||
unlock tables;
|
||||
#
|
||||
# Sic: lost handler position.
|
||||
#
|
||||
handler t1 read a next;
|
||||
a
|
||||
1
|
||||
3
|
||||
handler t1 close;
|
||||
drop table t1;
|
||||
#
|
||||
|
@ -412,9 +412,6 @@ flush tables t1 with read lock;
|
||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
||||
handler t1 read a next;
|
||||
unlock tables;
|
||||
--echo #
|
||||
--echo # Sic: lost handler position.
|
||||
--echo #
|
||||
handler t1 read a next;
|
||||
handler t1 close;
|
||||
drop table t1;
|
||||
|
@ -2010,117 +2010,6 @@ connection deadlock_con1;
|
||||
connection default;
|
||||
# Reaping ALTER. It should succeed and not produce ER_LOCK_DEADLOCK.
|
||||
drop table t1;
|
||||
#
|
||||
# Now, test for a situation in which deadlock involves waiting not
|
||||
# only in MDL subsystem but also for TDC. Such deadlocks should be
|
||||
# successfully detected. If possible, they should be resolved without
|
||||
# resorting to ER_LOCK_DEADLOCK error.
|
||||
#
|
||||
create table t1(i int);
|
||||
create table t2(j int);
|
||||
#
|
||||
# First, let us check how we handle a simple scenario involving
|
||||
# waits in MDL and TDC.
|
||||
#
|
||||
set debug_sync= 'RESET';
|
||||
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';
|
||||
disconnect deadlock_con1;
|
||||
disconnect deadlock_con2;
|
||||
|
@ -2493,170 +2493,6 @@ connection default;
|
||||
|
||||
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';
|
||||
|
||||
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)
|
||||
{
|
||||
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
||||
TABLE_LIST *table_list;
|
||||
|
||||
/*
|
||||
This is called from SQLCOM_FLUSH, the transaction has
|
||||
@ -545,17 +544,11 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
||||
|
||||
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
|
||||
|
||||
for (table_list= all_tables; table_list;
|
||||
table_list= table_list->next_global)
|
||||
{
|
||||
/* Request removal of table from cache. */
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
||||
table_list->db.str,
|
||||
table_list->table_name.str);
|
||||
/* Reset ticket to satisfy asserts in open_tables(). */
|
||||
for (auto table_list= all_tables; table_list;
|
||||
table_list= table_list->next_global)
|
||||
table_list->mdl_request.ticket= NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
goto error_reset_bits;
|
||||
|
||||
|
Reference in New Issue
Block a user