summaryrefslogtreecommitdiff
path: root/storage
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 /storage
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().
Diffstat (limited to 'storage')
-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
5 files changed, 32 insertions, 2 deletions
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;
+}