From b11772d9a54b596d56e071543e34692830068bbd Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 3 Apr 2025 16:43:01 +0530 Subject: [PATCH] MDEV-33167 ASAN errors in dict_sys_t::load_table / get_foreign_key_info after failing to load a table Problem: ======= - While loading the foreign key constraints for the parent table, if child table wasn't open then InnoDB uses the parent table heap to store the child table name in fk_tables list. If the consecutive foreign key relation for the parent table fails with error, InnoDB evicts the parent table from memory. But InnoDB accesses the evicted table memory again in dict_sys.load_table() Solution: ======== dict_load_table_one(): In case of error, remove the child table names which was added during dict_load_foreigns() --- mysql-test/suite/innodb/r/foreign_key.result | 21 +++++++++++-- mysql-test/suite/innodb/t/foreign_key.test | 32 +++++++++++++++++--- storage/innobase/dict/dict0load.cc | 2 ++ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index e7d0454df6e..236953795e6 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -155,7 +155,6 @@ INSERT INTO parent SET a=0; FLUSH TABLES; # restart disconnect incomplete; -SET @save_stats_persistent = @@GLOBAL.innodb_stats_persistent; SET GLOBAL innodb_stats_persistent = 0; INSERT INTO child SET a=0; INSERT INTO child SET a=1; @@ -1182,5 +1181,23 @@ ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fail ALTER TABLE t2 ADD KEY(b), ALGORITHM=NOCOPY; DELETE FROM t1; DROP TABLE t2, t1; +# +# MDEV-33167 ASAN errors after failing to load foreign key +# relation for the table +# +call mtr.add_suppression("InnoDB: Load table `test`.`t3` failed, the table has missing foreign key indexes. Turn off 'foreign_key_checks' and try again."); +SET STATEMENT FOREIGN_KEY_CHECKS = 0 FOR +CREATE TABLE t1(f1 VARCHAR(8), +FOREIGN KEY(f1) REFERENCES test.t3(f1))ENGINE=InnoDB; +SET STATEMENT FOREIGN_KEY_CHECKS = 0 FOR +CREATE TABLE t2(f1 VARCHAR(8), +FOREIGN KEY(f1) REFERENCES test.t3(f1)) +ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +SET STATEMENT FOREIGN_KEY_CHECKS = 0 FOR +CREATE TABLE t3(f1 VARCHAR(8) PRIMARY KEY) +ENGINE=InnoDB DEFAULT CHARSET=latin1; +set GLOBAL innodb_fast_shutdown=0; +# restart +ALTER TABLE t2 FORCE; +DROP TABLE t2, t1, t3; # End of 10.6 tests -SET GLOBAL innodb_stats_persistent = @save_stats_persistent; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 6a65de0e9b0..e7761f3cf4b 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -133,7 +133,6 @@ FLUSH TABLES; --let $shutdown_timeout= disconnect incomplete; -SET @save_stats_persistent = @@GLOBAL.innodb_stats_persistent; SET GLOBAL innodb_stats_persistent = 0; INSERT INTO child SET a=0; @@ -1245,8 +1244,31 @@ ALTER TABLE t2 ADD KEY(b), ALGORITHM=NOCOPY; DELETE FROM t1; DROP TABLE t2, t1; +--echo # +--echo # MDEV-33167 ASAN errors after failing to load foreign key +--echo # relation for the table +--echo # +call mtr.add_suppression("InnoDB: Load table `test`.`t3` failed, the table has missing foreign key indexes. Turn off 'foreign_key_checks' and try again."); +SET STATEMENT FOREIGN_KEY_CHECKS = 0 FOR +CREATE TABLE t1(f1 VARCHAR(8), + FOREIGN KEY(f1) REFERENCES test.t3(f1))ENGINE=InnoDB; + +SET STATEMENT FOREIGN_KEY_CHECKS = 0 FOR +CREATE TABLE t2(f1 VARCHAR(8), + FOREIGN KEY(f1) REFERENCES test.t3(f1)) + ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +SET STATEMENT FOREIGN_KEY_CHECKS = 0 FOR +CREATE TABLE t3(f1 VARCHAR(8) PRIMARY KEY) + ENGINE=InnoDB DEFAULT CHARSET=latin1; + +set GLOBAL innodb_fast_shutdown=0; +--let $shutdown_timeout= +--source include/restart_mysqld.inc +# Error encountered while loading the foreign key +# constraint for t3. t1 wasn't loaded into memory yet +# t2 failed to find index for foreign key relation +ALTER TABLE t2 FORCE; +DROP TABLE t2, t1, t3; + --echo # End of 10.6 tests - -SET GLOBAL innodb_stats_persistent = @save_stats_persistent; - ---source include/wait_until_count_sessions.inc diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 917c4d51ee9..0071e7e8afe 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2515,10 +2515,12 @@ corrupted: if (!table->is_readable()) { /* Don't attempt to load the indexes from disk. */ } else if (err == DB_SUCCESS) { + auto i = fk_tables.size(); err = dict_load_foreigns(table->name.m_name, nullptr, 0, true, ignore_err, fk_tables); if (err != DB_SUCCESS) { + fk_tables.erase(fk_tables.begin() + i, fk_tables.end()); ib::warn() << "Load table " << table->name << " failed, the table has missing" " foreign key indexes. Turn off"