summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2021-04-27 16:46:54 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2021-04-27 17:07:37 +0530
commitb862377c3e9a6818bc2d5265c19edeee79a293fc (patch)
treea03df6b1a347438b18208099fa28ef31104373f7
parent2b0d5b78c2bbe2bdd763a8e2ed12be644bd705d2 (diff)
downloadmariadb-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.result15
-rw-r--r--mysql-test/suite/innodb/t/innodb-alter-tempfile.test22
-rw-r--r--storage/innobase/dict/dict0dict.cc6
-rw-r--r--storage/innobase/include/dict0mem.h5
-rw-r--r--storage/innobase/include/trx0trx.h4
-rw-r--r--storage/innobase/trx/trx0roll.cc6
-rw-r--r--storage/innobase/trx/trx0trx.cc13
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;
+}