Commit 14a18d7d authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-23026/MDEV-25474 fixup: Assertion ib_table->stat_initialized

It is possible that an object that was originally created by
open_purge_table() will remain cached and reused for SQL execution.
Our previous fix wrongly assumed that ha_innobase::open() would
always be called before SQL execution starts. Therefore, we must
invoke dict_stats_init() in ha_innobase::info_low() instead of
only doing it in ha_innobase::open().

Note: Concurrent execution of dict_stats_init() on the same table
is possible, but it also was possible between two calls to
ha_innobase::open(), with no ill effects observed.

This should fix the assertion failure on stat_initialized.
A possibly easy way to reproduce it would have been
to run the server with innodb_force_recovery=2 (disable the purge of
history), update a table so that an indexed virtual column will be
affected, and finally restart the server normally (purge enabled),
to observe a crash when the table is accessed from SQL.

The problem was first observed and this fix verified by
Elena Stepanova. Also Thirunarayanan Balathandayuthapani
repeated the problem.
parent 25ed665a
......@@ -6261,16 +6261,6 @@ ha_innobase::open(const char* name, int, uint)
innobase_copy_frm_flags_from_table_share(ib_table, table->s);
const bool bk_thread = THDVAR(thd, background_thread);
/* No point to init any statistics if tablespace is still encrypted
or if table is being opened by background thread */
if (bk_thread) {
} else if (ib_table->is_readable()) {
dict_stats_init(ib_table);
} else {
ib_table->stat_initialized = 1;
}
MONITOR_INC(MONITOR_TABLE_OPEN);
bool no_tablespace = false;
......@@ -6516,7 +6506,7 @@ ha_innobase::open(const char* name, int, uint)
}
}
if (!bk_thread) {
if (!THDVAR(thd, background_thread)) {
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
}
......@@ -14399,6 +14389,10 @@ ha_innobase::info_low(
ib_table = m_prebuilt->table;
DBUG_ASSERT(ib_table->get_ref_count() > 0);
if (!ib_table->is_readable()) {
ib_table->stat_initialized = true;
}
if (flag & HA_STATUS_TIME) {
if (is_analyze || innobase_stats_on_metadata) {
......@@ -14449,6 +14443,8 @@ ha_innobase::info_low(
stats.update_time = (ulong) ib_table->update_time;
}
dict_stats_init(ib_table);
if (flag & HA_STATUS_VARIABLE) {
ulint stat_clustered_index_size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment