From fc391df54698fccf08e6299b208badc74c82cd1c Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 28 Apr 2022 15:15:37 +0530 Subject: [PATCH] MDEV-28399 Assertion failure in dict_table_check_for_dup_indexes upon concurrent DML/DDL Problem: ======== InnoDB DDL fails to remove the newly added table or index from dictionary and index stub from the table cache if the alter transaction encounters DEADLOCK error in commit phase. Solution: ======== Restart the alter table transaction if it encounters DEADLOCK in commit phase. So that index stubs and index, table removal from dictionary can be done in rollback_inplace_alter_table() - Added one assert in rollback_inplace_alter_table() to indicate that the online log for the old table shouldn't exist. --- .../suite/innodb/r/innodb-alter-debug.result | 2 +- .../suite/innodb/t/innodb-alter-debug.test | 2 +- storage/innobase/handler/handler0alter.cc | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-alter-debug.result b/mysql-test/suite/innodb/r/innodb-alter-debug.result index aae9432fc35..8962d6ba400 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-debug.result +++ b/mysql-test/suite/innodb/r/innodb-alter-debug.result @@ -134,7 +134,7 @@ DROP TABLE t1; # CREATE TABLE t1(a INT PRIMARY KEY, b INT, INDEX(b)) ENGINE=InnoDB; SET @save_dbug=@@debug_dbug; -SET debug_dbug='+d,innodb_table_deadlock'; +SET debug_dbug='+d,deadlock_table_fail'; ALTER TABLE t1 DROP INDEX b, ALGORITHM=INPLACE; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction SET debug_dbug=@save_dbug; diff --git a/mysql-test/suite/innodb/t/innodb-alter-debug.test b/mysql-test/suite/innodb/t/innodb-alter-debug.test index 2241ef5d295..c4a68ac71b7 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-debug.test +++ b/mysql-test/suite/innodb/t/innodb-alter-debug.test @@ -180,7 +180,7 @@ DROP TABLE t1; CREATE TABLE t1(a INT PRIMARY KEY, b INT, INDEX(b)) ENGINE=InnoDB; SET @save_dbug=@@debug_dbug; -SET debug_dbug='+d,innodb_table_deadlock'; +SET debug_dbug='+d,deadlock_table_fail'; --error ER_LOCK_DEADLOCK ALTER TABLE t1 DROP INDEX b, ALGORITHM=INPLACE; SET debug_dbug=@save_dbug; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1b184422a80..c2dc68f18d0 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8884,6 +8884,7 @@ free_and_exit: } } + DBUG_ASSERT(!prebuilt->table->indexes.start->online_log); DBUG_ASSERT(prebuilt->table->indexes.start->online_status == ONLINE_INDEX_COMPLETE); @@ -10938,6 +10939,12 @@ ha_innobase::commit_inplace_alter_table( LOCK_X); } + DBUG_EXECUTE_IF("deadlock_table_fail", + { + error= DB_DEADLOCK; + trx_rollback_for_mysql(trx); + }); + if (error != DB_SUCCESS) { lock_fail: my_error_innodb( @@ -10945,6 +10952,16 @@ lock_fail: if (fts_exist) { purge_sys.resume_FTS(); } + + /* Deadlock encountered and rollbacked the + transaction. So restart the transaction + to remove the newly created table or + index from data dictionary and table cache + in rollback_inplace_alter_table() */ + if (trx->state == TRX_STATE_NOT_STARTED) { + trx_start_for_ddl(trx); + } + DBUG_RETURN(true); } else if ((ctx->new_table->flags2 & (DICT_TF2_FTS_HAS_DOC_ID | DICT_TF2_FTS))