diff options
-rw-r--r-- | mysql-test/suite/innodb/r/alter_mdl_timeout.result | 23 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/alter_mdl_timeout.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/alter_mdl_timeout.test | 32 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 33 |
4 files changed, 87 insertions, 2 deletions
diff --git a/mysql-test/suite/innodb/r/alter_mdl_timeout.result b/mysql-test/suite/innodb/r/alter_mdl_timeout.result new file mode 100644 index 00000000000..7af1362c69e --- /dev/null +++ b/mysql-test/suite/innodb/r/alter_mdl_timeout.result @@ -0,0 +1,23 @@ +create table t1(f1 char(10), f2 char(10) not null, f3 int not null, +f4 int not null, primary key(f3))engine=innodb; +insert into t1 values('a','a', 1, 1), ('b','b', 2, 2), ('c', 'c', 3, 3), ('d', 'd', 4, 4); +SET DEBUG_SYNC="row_merge_after_scan SIGNAL con1_start WAIT_FOR con1_insert"; +SET DEBUG_SYNC="innodb_commit_inplace_alter_table_wait SIGNAL con1_wait WAIT_FOR con1_update"; +ALTER TABLE t1 ADD UNIQUE INDEX(f1(3), f4), ADD UNIQUE INDEX(f2), ALGORITHM=INPLACE; +connect con1,localhost,root,,,; +SET DEBUG_SYNC="now WAIT_FOR con1_start"; +begin; +INSERT INTO t1 VALUES('e','e',5, 5); +SET DEBUG_SYNC="now SIGNAL con1_insert"; +SET DEBUG_SYNC="now WAIT_FOR con1_wait"; +SET DEBUG_SYNC="before_row_upd_sec_new_index_entry SIGNAL con1_update WAIT_FOR alter_rollback"; +UPDATE t1 set f4 = 10 order by f1 desc limit 2; +connection default; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SET DEBUG_SYNC="now SIGNAL alter_rollback"; +connection con1; +commit; +connection default; +disconnect con1; +DROP TABLE t1; +SET DEBUG_SYNC="RESET"; diff --git a/mysql-test/suite/innodb/t/alter_mdl_timeout.opt b/mysql-test/suite/innodb/t/alter_mdl_timeout.opt new file mode 100644 index 00000000000..9e0e38bd64a --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_mdl_timeout.opt @@ -0,0 +1 @@ +--lock_wait_timeout=2 diff --git a/mysql-test/suite/innodb/t/alter_mdl_timeout.test b/mysql-test/suite/innodb/t/alter_mdl_timeout.test new file mode 100644 index 00000000000..15e7f524fd0 --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_mdl_timeout.test @@ -0,0 +1,32 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +create table t1(f1 char(10), f2 char(10) not null, f3 int not null, + f4 int not null, primary key(f3))engine=innodb; +insert into t1 values('a','a', 1, 1), ('b','b', 2, 2), ('c', 'c', 3, 3), ('d', 'd', 4, 4); +SET DEBUG_SYNC="row_merge_after_scan SIGNAL con1_start WAIT_FOR con1_insert"; +SET DEBUG_SYNC="innodb_commit_inplace_alter_table_wait SIGNAL con1_wait WAIT_FOR con1_update"; +send ALTER TABLE t1 ADD UNIQUE INDEX(f1(3), f4), ADD UNIQUE INDEX(f2), ALGORITHM=INPLACE; + +connect(con1,localhost,root,,,); +SET DEBUG_SYNC="now WAIT_FOR con1_start"; +begin; +INSERT INTO t1 VALUES('e','e',5, 5); +SET DEBUG_SYNC="now SIGNAL con1_insert"; +SET DEBUG_SYNC="now WAIT_FOR con1_wait"; +SET DEBUG_SYNC="before_row_upd_sec_new_index_entry SIGNAL con1_update WAIT_FOR alter_rollback"; +SEND UPDATE t1 set f4 = 10 order by f1 desc limit 2; + +connection default; +--error ER_LOCK_WAIT_TIMEOUT +reap; +SET DEBUG_SYNC="now SIGNAL alter_rollback"; + +connection con1; +reap; +commit; + +connection default; +disconnect con1; +DROP TABLE t1; +SET DEBUG_SYNC="RESET"; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 10156c7d3ab..51e8246e80a 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2020, MariaDB Corporation. +Copyright (c) 2015, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2320,7 +2320,9 @@ row_upd_sec_index_entry( break; } - if (!index->is_committed()) { + bool uncommitted = !index->is_committed(); + + if (uncommitted) { /* The index->online_status may change if the index is or was being created online, but not committed yet. It is protected by index->lock. */ @@ -2517,11 +2519,38 @@ row_upd_sec_index_entry( mem_heap_empty(heap); + DEBUG_SYNC_C_IF_THD(trx->mysql_thd, + "before_row_upd_sec_new_index_entry"); + + uncommitted = !index->is_committed(); + if (uncommitted) { + mtr.start(); + /* The index->online_status may change if the index is + being rollbacked. It is protected by index->lock. */ + + mtr_s_lock(dict_index_get_lock(index), &mtr); + + switch (dict_index_get_online_status(index)) { + case ONLINE_INDEX_COMPLETE: + case ONLINE_INDEX_CREATION: + break; + case ONLINE_INDEX_ABORTED: + case ONLINE_INDEX_ABORTED_DROPPED: + mtr_commit(&mtr); + goto func_exit; + } + + } + /* Build a new index entry */ entry = row_build_index_entry(node->upd_row, node->upd_ext, index, heap); ut_a(entry); + if (uncommitted) { + mtr_commit(&mtr); + } + /* Insert new index entry */ err = row_ins_sec_index_entry(index, entry, thr); |