Skip to content

Commit 978e48c

Browse files
committed
MDEV-25051 Race condition between persistent statistics and RENAME TABLE or TRUNCATE
innobase_rename_table(): Invoke dict_stats_wait_bg_to_stop_using_table() to ensure that dict_stats_update() cannot be accessing the table name that we will be modifying. If we are executing RENAME rather than TRUNCATE, reset the flag at the end so that persistent statistics can be calculated again. The race condition was encountered with ASAN and rr. Sorry, there is no test case, like there is for nothing related to dict_stats_wait_bg_to_stop_using_table(). The entire code is an ugly work-around for the failure of dict_stats_process_entry_from_recalc_pool() to acquire MDL. Note: It appears that an ALTER TABLE that is not rebuilding the table will fail to reset the flag that blocks the processing of statistics.
1 parent 5da6ffe commit 978e48c

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

storage/innobase/handler/ha_innodb.cc

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13518,17 +13518,10 @@ innobase_drop_database(
1351813518
@param[in,out] trx InnoDB data dictionary transaction
1351913519
@param[in] from old table name
1352013520
@param[in] to new table name
13521-
@param[in] commit whether to commit trx
13522-
@param[in] use_fk whether to parse and enforce FOREIGN KEY constraints
13521+
@param[in] commit whether to commit trx (and to enforce FOREIGN KEY)
1352313522
@return DB_SUCCESS or error code */
13524-
inline
13525-
dberr_t
13526-
innobase_rename_table(
13527-
trx_t* trx,
13528-
const char* from,
13529-
const char* to,
13530-
bool commit,
13531-
bool use_fk)
13523+
inline dberr_t innobase_rename_table(trx_t *trx, const char *from,
13524+
const char *to, bool commit)
1353213525
{
1353313526
dberr_t error;
1353413527
char norm_to[FN_REFLEN];
@@ -13561,6 +13554,9 @@ innobase_rename_table(
1356113554
Convert lock_wait_timeout unit from second to 250 milliseconds */
1356213555
long int lock_wait_timeout = thd_lock_wait_timeout(trx->mysql_thd) * 4;
1356313556
if (table != NULL) {
13557+
if (commit) {
13558+
dict_stats_wait_bg_to_stop_using_table(table, trx);
13559+
}
1356413560
for (dict_index_t* index = dict_table_get_first_index(table);
1356513561
index != NULL;
1356613562
index = dict_table_get_next_index(index)) {
@@ -13574,7 +13570,9 @@ innobase_rename_table(
1357413570
}
1357513571
}
1357613572
}
13577-
dict_table_close(table, TRUE, FALSE);
13573+
if (!commit) {
13574+
dict_table_close(table, TRUE, FALSE);
13575+
}
1357813576
}
1357913577

1358013578
/* FTS sync is in progress. We shall timeout this operation */
@@ -13589,7 +13587,7 @@ innobase_rename_table(
1358913587
ut_a(trx->will_lock > 0);
1359013588

1359113589
error = row_rename_table_for_mysql(norm_from, norm_to, trx, commit,
13592-
use_fk);
13590+
commit);
1359313591

1359413592
if (error != DB_SUCCESS) {
1359513593
if (error == DB_TABLE_NOT_FOUND
@@ -13641,6 +13639,10 @@ innobase_rename_table(
1364113639

1364213640
func_exit:
1364313641
if (commit) {
13642+
if (table) {
13643+
table->stats_bg_flag &= ~BG_STAT_SHOULD_QUIT;
13644+
dict_table_close(table, TRUE, FALSE);
13645+
}
1364413646
row_mysql_unlock_data_dictionary(trx);
1364513647
}
1364613648

@@ -13726,9 +13728,11 @@ int ha_innobase::truncate()
1372613728
++trx->will_lock;
1372713729
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1372813730
row_mysql_lock_data_dictionary(trx);
13731+
dict_stats_wait_bg_to_stop_using_table(ib_table, trx);
13732+
1372913733
int err = convert_error_code_to_mysql(
1373013734
innobase_rename_table(trx, ib_table->name.m_name, temp_name,
13731-
false, false),
13735+
false),
1373213736
ib_table->flags, m_user_thd);
1373313737
if (err) {
1373413738
trx_rollback_for_mysql(trx);
@@ -13811,7 +13815,7 @@ ha_innobase::rename_table(
1381113815
++trx->will_lock;
1381213816
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1381313817

13814-
dberr_t error = innobase_rename_table(trx, from, to, true, true);
13818+
dberr_t error = innobase_rename_table(trx, from, to, true);
1381513819

1381613820
DEBUG_SYNC(thd, "after_innobase_rename_table");
1381713821

0 commit comments

Comments
 (0)