diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2021-04-27 16:46:54 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2021-04-27 17:07:37 +0530 |
commit | b862377c3e9a6818bc2d5265c19edeee79a293fc (patch) | |
tree | a03df6b1a347438b18208099fa28ef31104373f7 | |
parent | 2b0d5b78c2bbe2bdd763a8e2ed12be644bd705d2 (diff) | |
download | mariadb-git-b862377c3e9a6818bc2d5265c19edeee79a293fc.tar.gz |
MDEV-25503 InnoDB hangs on startup during recovery
InnoDB startup hangs if a DDL transaction needs to be
rolled back and a recovered transaction on statistics
tables exists. In that case, InnoDB should rollback
the transaction which holds locks on innodb_table_stats
or innodb_index_stats during trx_rollback_or_clean_recovered().
-rw-r--r-- | mysql-test/suite/innodb/r/innodb-alter-tempfile.result | 15 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/innodb-alter-tempfile.test | 22 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 6 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 5 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 4 | ||||
-rw-r--r-- | storage/innobase/trx/trx0roll.cc | 6 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 13 |
7 files changed, 69 insertions, 2 deletions
diff --git a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result index 7441cc23594..ad6e17b920c 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result +++ b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result @@ -50,3 +50,18 @@ Warnings: Warning 1082 InnoDB: Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB Warning 1082 InnoDB: Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB DROP TABLE t1; +# +# MDEV-25503 InnoDB hangs on startup during recovery +# +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1; +connect con1,localhost,root,,; +BEGIN; +DELETE FROM mysql.innodb_table_stats; +connect con2,localhost,root,,; +SET DEBUG_SYNC='inplace_after_index_build SIGNAL blocked WAIT_FOR ever'; +ALTER TABLE t1 FORCE; +connection default; +SET DEBUG_SYNC='now WAIT_FOR blocked'; +SELECT * FROM t1; +a +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test index e6fafd936c8..7e4244d09f8 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test +++ b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test @@ -12,6 +12,8 @@ --source include/innodb_page_size.inc +--source include/have_debug_sync.inc + call mtr.add_suppression("Cannot find index f2 in InnoDB index dictionary."); call mtr.add_suppression("InnoDB indexes are inconsistent with what defined in .frm for table .*"); call mtr.add_suppression("Table test/t1 contains 1 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB .*"); @@ -69,3 +71,23 @@ disconnect con1; SHOW KEYS FROM t1; DROP TABLE t1; remove_files_wildcard $datadir/test #sql-*.frm; + +--echo # +--echo # MDEV-25503 InnoDB hangs on startup during recovery +--echo # +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1; +connect (con1,localhost,root,,); +BEGIN; +DELETE FROM mysql.innodb_table_stats; + +connect (con2,localhost,root,,); +SET DEBUG_SYNC='inplace_after_index_build SIGNAL blocked WAIT_FOR ever'; +send ALTER TABLE t1 FORCE; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR blocked'; +--let $shutdown_timeout=0 +--source include/restart_mysqld.inc +SELECT * FROM t1; +DROP TABLE t1; +remove_files_wildcard $datadir/test #sql-*.frm; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index d6330cb5906..48c37855d3e 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -6719,3 +6719,9 @@ dict_table_t::get_overflow_field_local_len() const /* new-format table: do not store any BLOB prefix locally */ return BTR_EXTERN_FIELD_REF_SIZE; } + +bool dict_table_t::is_stats_table() const +{ + return !strcmp(name.m_name, TABLE_STATS_NAME) || + !strcmp(name.m_name, INDEX_STATS_NAME); +} diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 7ca1ad9ecd3..ae7f00c01bf 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1935,6 +1935,11 @@ public: return true; return false; } + + /** Check whether the table name is same as mysql/innodb_stats_table + or mysql/innodb_index_stats. + @return true if the table name is same as stats table */ + bool is_stats_table() const; }; inline bool table_name_t::is_temporary() const diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 5354c77db25..a7591fa1b19 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1191,6 +1191,10 @@ public: ut_ad(old_n_ref > 0); } + /** @return whether the table has lock on + mysql.innodb_table_stats and mysql.innodb_index_stats */ + bool has_stats_table_lock() const; + /** Free the memory to trx_pools */ inline void free(); diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index c5f70452bf2..c986a866fe2 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -677,7 +677,8 @@ ibool trx_rollback_resurrected( /*=====================*/ trx_t* trx, /*!< in: transaction to rollback or clean */ - ibool* all) /*!< in/out: FALSE=roll back dictionary transactions; + ibool* all) /*!< in/out: FALSE=roll back dictionary and + statistics table transactions; TRUE=roll back all non-PREPARED transactions */ { ut_ad(trx_sys_mutex_own()); @@ -713,7 +714,8 @@ fake_prepared: } trx_mutex_exit(trx); - if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) { + if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE + || trx->has_stats_table_lock()) { trx_sys_mutex_exit(); trx_rollback_active(trx); if (trx->error_state != DB_SUCCESS) { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 42bd67cb24b..e3df3f397a5 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -3072,3 +3072,16 @@ trx_set_rw_mode( mutex_exit(&trx_sys->mutex); } + +bool trx_t::has_stats_table_lock() const +{ + for (lock_list::const_iterator it= lock.table_locks.begin(), + end= lock.table_locks.end(); it != end; ++it) + { + const lock_t *lock= *it; + if (lock && lock->un_member.tab_lock.table->is_stats_table()) + return true; + } + + return false; +} |