Skip to content
Permalink
Browse files
MDEV-29566 Failed to read from the .par file upon concurrent DDL/SELE…
…CT 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.
  • Loading branch information
dr-m committed Sep 26, 2022
1 parent 829e811 commit bdc5548
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 1 deletion.
@@ -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) &&

0 comments on commit bdc5548

Please sign in to comment.