MDEV-24547 Update fails when online alter does rollback due to MDL time out

When online alter rollbacks due to MDL time out, it doesn't mark the
index online status as ONLINE_INDEX_ABORTED. Concurrent update fails
to update the secondary index while building the entry.
InnoDB should check the online status of the secondary index before
building the secondary index entry.

Reviewed-by: Marko Mäkelä
parent 94890a74
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";
--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";
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -2320,7 +2320,9 @@ row_upd_sec_index_entry( ...@@ -2320,7 +2320,9 @@ row_upd_sec_index_entry(
break; break;
} }
if (!index->is_committed()) { bool uncommitted = !index->is_committed();
if (uncommitted) {
/* The index->online_status may change if the index is /* The index->online_status may change if the index is
or was being created online, but not committed yet. It or was being created online, but not committed yet. It
is protected by index->lock. */ is protected by index->lock. */
...@@ -2517,11 +2519,38 @@ row_upd_sec_index_entry( ...@@ -2517,11 +2519,38 @@ row_upd_sec_index_entry(
mem_heap_empty(heap); 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 */ /* Build a new index entry */
entry = row_build_index_entry(node->upd_row, node->upd_ext, entry = row_build_index_entry(node->upd_row, node->upd_ext,
index, heap); index, heap);
ut_a(entry); ut_a(entry);
if (uncommitted) {
mtr_commit(&mtr);
}
/* Insert new index entry */ /* Insert new index entry */
err = row_ins_sec_index_entry(index, entry, thr); err = row_ins_sec_index_entry(index, entry, thr);
......
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