Skip to content
/ server Public

Comments

MDEV-38822: Fix self-deadlock on CTAS from innodb stats tables#4669

Open
OmarGamal10 wants to merge 1 commit intoMariaDB:10.6from
OmarGamal10:mdev-38822
Open

MDEV-38822: Fix self-deadlock on CTAS from innodb stats tables#4669
OmarGamal10 wants to merge 1 commit intoMariaDB:10.6from
OmarGamal10:mdev-38822

Conversation

@OmarGamal10
Copy link

@OmarGamal10 OmarGamal10 commented Feb 19, 2026

Cause

  • Running a CTAS like create table t1_stat as SELECT * FROM mysql.innodb_table_stats; causes a lock_wait_timeout on updating stats warning.
  • From this stack trace, this happens due to the thread still acquiring a Shared_lock and then attempting to acquire an Exclusive_lock on the stats table, resulting in the deadlock.
#7  0x0000555556028f8a in lock_table_for_trx (table=0x55555893b3f8, trx=0x7ffff4353780, mode=LOCK_X, no_wait=false)
#10 0x0000555555f7562e in alter_stats_rebuild (table=0x7fffa0033738, thd=0x7fffa0000e38)
#21 0x00005555556dced4 in mysql_parse (thd=0x7fffa0000e38, rawbuf=0x7fffa00143b0 "create table t2_stat as select * from mysql.innodb_table_stats where table_name='t1'", length=84, parser_state=0x7ffff40b4fd0)
#22 0x00005555556c6fd9 in dispatch_command (command=COM_QUERY, thd=0x7fffa0000e38, packet=0x7fffa000ba59 "create table t2_stat as select * from mysql.innodb_table_stats where table_name='t1'", packet_length=84, blocking=true)

Fix

  • I noticed the stats_table gets indeed updated after the timeout, this is due to the innodb_stats_auto_recalc global variable being ON, which optimistically uses a background thread to update the stats table.
  • The solution checks for a Create query using one of the innodb system tables mysql.innodb_[table/index]_stats, and delegates the stats rebuild into the background pool regardless of the value innodb_stats_auto_recalc.

Note: I though about maybe upgrading the shared lock to an exclusive one since the problem is caused by the owner thread only, but this can have other implications for shared behavior, so I went with the above approach.

@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Feb 20, 2026
Copy link
Member

@gkodinov gkodinov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution. This is a preliminary review.

In addition to the suggestions below, please squash all of your commits into a single one and make sure it has a message that follows CODING_STANDARDS.md.

DROP TABLE t1;
DROP TABLE t2;
#
# MDEV-38667 Assertion in diagnostics area on DDL stats timeout
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a note on MDEV-38667 that the current change further addresses the same issue.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean adding a note on the topic on Jira?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. You are altering the test added through that Jira. So it'd be polite to add an update to it so that people watching it will get a notification.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I added a comment there explaining the change.

SELECT COUNT(*) as n_rows FROM t;
n_rows
1
# For a deterministic test, we wait for the background thread to update the stats for the new table.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, (not really insisting on it and hope the final reviewer would consider it) you could use the DBUG library to produce the effect: https://mariadb.com/docs/server/clients-and-utilities/testing-tools/mariadb-test/the-debug-sync-facility.

I'd give it a couple of hours to try and reproduce it by dipping in DBUG_SYNC points and running two threads in mariadb-test.

const char *innodb_table_stats= "innodb_table_stats";
const char *innodb_index_stats= "innodb_index_stats";

if (strstr((const char *) q->str, innodb_table_stats) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a terrible way to check if a table is used! Please consider something more robust.
I'd add a thd_sql_is_table_accessed() that would read THD::open_tables and check if the table I need is there.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right. I overlooked this and focused more on locating the issue itself. I used external linkage in ha_innodb.cc because the public ABI in mysql/plugin.h is normally strict with such additions.

…l.innodb_table_stats

Fixes the lock wait timeout when using a CTAS query from InnoDB stats
tables. This normally leads to a timeout warning and may skip updating
the stats tables if innodb_stats_auto is OFF. This patch identifies this
behavior and delegates the stats rebuild to the background pool to avoid
self-deadlock.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

2 participants