Commit bdc5548c authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-29566 Failed to read from the .par file upon concurrent DDL/SELECT with partition pruning

ha_innobase::delete_table(): If locking the InnoDB persistent statistics
tables mysql.innodb_table_stats or mysql.innodb_index_stats fails for
a table partition, proceed to drop the partition. On DROP TABLE of a
partitioned table, each partition is being dropped in a separate
InnoDB DDL transaction. The only practical way to create an illusion of
atomicity is to avoid failures.
parent 829e8111
......@@ -2,6 +2,8 @@ CREATE DATABASE unlocked;
CREATE TABLE unlocked.t1(a INT PRIMARY KEY) ENGINE=INNODB STATS_PERSISTENT=0;
CREATE DATABASE locked;
CREATE TABLE locked.t1(a INT PRIMARY KEY) ENGINE=INNODB STATS_PERSISTENT=1;
CREATE TABLE locked.t1p(pk INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1
PARTITION BY HASH (pk) PARTITIONS 4;
CREATE TABLE innodb_stats_drop_locked (c INT, KEY c_key (c))
ENGINE=INNODB STATS_PERSISTENT=1;
ANALYZE TABLE innodb_stats_drop_locked;
......@@ -38,12 +40,25 @@ innodb_stats_drop_locked CREATE TABLE `innodb_stats_drop_locked` (
DROP TABLE innodb_stats_drop_locked;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
DROP DATABASE unlocked;
DROP TABLE locked.t1p;
SELECT * FROM locked.t1p;
ERROR 42S02: Table 'locked.t1p' doesn't exist
DROP DATABASE locked;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
disconnect con1;
connection default;
COMMIT;
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE database_name='locked';
COUNT(*)
5
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE database_name='locked';
COUNT(*)
15
DROP DATABASE locked;
SELECT table_name FROM mysql.innodb_table_stats WHERE database_name='locked';
table_name
SELECT table_name FROM mysql.innodb_index_stats WHERE database_name='locked';
table_name
SELECT table_name FROM mysql.innodb_table_stats
WHERE table_name='innodb_stats_drop_locked';
table_name
......
......@@ -4,12 +4,16 @@
#
-- source include/have_innodb.inc
-- source include/have_partition.inc
CREATE DATABASE unlocked;
CREATE TABLE unlocked.t1(a INT PRIMARY KEY) ENGINE=INNODB STATS_PERSISTENT=0;
CREATE DATABASE locked;
CREATE TABLE locked.t1(a INT PRIMARY KEY) ENGINE=INNODB STATS_PERSISTENT=1;
CREATE TABLE locked.t1p(pk INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1
PARTITION BY HASH (pk) PARTITIONS 4;
CREATE TABLE innodb_stats_drop_locked (c INT, KEY c_key (c))
ENGINE=INNODB STATS_PERSISTENT=1;
ANALYZE TABLE innodb_stats_drop_locked;
......@@ -35,14 +39,26 @@ SHOW CREATE TABLE innodb_stats_drop_locked;
DROP TABLE innodb_stats_drop_locked;
DROP DATABASE unlocked;
# Partitions will always be dropped despite locking conflicts.
DROP TABLE locked.t1p;
--error ER_NO_SUCH_TABLE
SELECT * FROM locked.t1p;
--error ER_LOCK_WAIT_TIMEOUT
DROP DATABASE locked;
-- disconnect con1
-- connection default
COMMIT;
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE database_name='locked';
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE database_name='locked';
DROP DATABASE locked;
SELECT table_name FROM mysql.innodb_table_stats WHERE database_name='locked';
SELECT table_name FROM mysql.innodb_index_stats WHERE database_name='locked';
# the stats should be there
SELECT table_name FROM mysql.innodb_table_stats
......
......@@ -13613,7 +13613,8 @@ int ha_innobase::delete_table(const char *name)
dict_sys.unfreeze();
}
const bool skip_wait{table->name.is_temporary()};
const bool skip_wait{table->name.is_temporary() ||
dict_table_is_partition(table)};
if (table_stats && index_stats &&
!strcmp(table_stats->name.m_name, TABLE_STATS_NAME) &&
......
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