From 6e0f4560902088a98a4e8ff1643d730bcc2d4aba Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Wed, 29 Jun 2022 23:32:19 +0300 Subject: [PATCH] MDEV-29013 ER_KEY_NOT_FOUND/lock timeout upon online alter with long unique 1. ER_KEY_NOT_FOUND general replcation problem, already fixed earlier. test added. 2. ER_LOCK_WAIT_TIMEOUT This is a long unique specific problem. Sometimes, lookup_handler is created for to->file. To properly free it, ha_reset should be called. It is usually done by calling close_thread_table, but ALTER TABLE makes it differently. Hence, a single ha_reset call is added to mysql_alter_table. Also, event_mem_root is removed. Normally, no per-event data should be allocated on thd->mem_root, that would mean a leak. And otherwise, lookup_handler is lazily allocated, but its lifetime matches statement, not event. --- .../main/alter_table_online_debug.result | 34 ++++++++++++ mysql-test/main/alter_table_online_debug.test | 54 +++++++++++++++++++ sql/sql_table.cc | 10 ---- sql/temporary_tables.cc | 3 +- 4 files changed, 89 insertions(+), 12 deletions(-) diff --git a/mysql-test/main/alter_table_online_debug.result b/mysql-test/main/alter_table_online_debug.result index 589c6b55f8d..7c5fae54759 100644 --- a/mysql-test/main/alter_table_online_debug.result +++ b/mysql-test/main/alter_table_online_debug.result @@ -918,5 +918,39 @@ a b drop table t1; set debug_sync= 'reset'; # +# MDEV-29013 ER_KEY_NOT_FOUND/lock timeout upon online alter +# with long unique indexes +# +create table t1 (b text not null, unique(b)); +insert into t1 values ('foo'),('bar'); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t1 add c int, algorithm=copy, lock=none; +connection default; +delete from t1; +set debug_sync= 'now signal goforit'; +connection con2; +connection default; +drop table t1; +set debug_sync= reset; +### +create table t1 (a text, unique(a)) engine=innodb; +create table t2 (b text, unique(b)) engine=innodb; +insert into t2 values (null),(null); +set debug_sync= 'now wait_for downgraded'; +connection con2; +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +alter table t2 add column c int, algorithm=copy, lock=none; +connection default; +delete from t2; +set debug_sync= 'now signal goforit'; +connection con2; +connection default; +alter table t2 force; +alter table t1 force; +drop table t1, t2; +set debug_sync= reset; +# # End of 11.2 tests # diff --git a/mysql-test/main/alter_table_online_debug.test b/mysql-test/main/alter_table_online_debug.test index 62bed3997aa..9e0a47758c8 100644 --- a/mysql-test/main/alter_table_online_debug.test +++ b/mysql-test/main/alter_table_online_debug.test @@ -1059,6 +1059,60 @@ select * from t1; drop table t1; set debug_sync= 'reset'; +--echo # +--echo # MDEV-29013 ER_KEY_NOT_FOUND/lock timeout upon online alter +--echo # with long unique indexes +--echo # +create table t1 (b text not null, unique(b)); +insert into t1 values ('foo'),('bar'); +--send +set debug_sync= 'now wait_for downgraded'; + +--connection con2 +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +--send +alter table t1 add c int, algorithm=copy, lock=none; + +--connection default +--reap +delete from t1; +set debug_sync= 'now signal goforit'; + +--connection con2 +--reap + +--connection default +drop table t1; +set debug_sync= reset; + +--echo ### + +create table t1 (a text, unique(a)) engine=innodb; +create table t2 (b text, unique(b)) engine=innodb; +insert into t2 values (null),(null); +--send +set debug_sync= 'now wait_for downgraded'; + +--connection con2 +set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit'; +--send +alter table t2 add column c int, algorithm=copy, lock=none; + +--connection default +--reap +delete from t2; +set debug_sync= 'now signal goforit'; + +--connection con2 +--reap + +--connection default +alter table t2 force; +alter table t1 force; + +drop table t1, t2; +set debug_sync= reset; + --echo # --echo # End of 11.2 tests --echo # diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9bcfd304f4e..0a69505de47 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -11556,12 +11556,6 @@ public: static int online_alter_read_from_binlog(THD *thd, rpl_group_info *rgi, Cache_flip_event_log *log) { - MEM_ROOT event_mem_root; - Query_arena backup_arena; - Query_arena event_arena(&event_mem_root, Query_arena::STMT_INITIALIZED); - init_sql_alloc(key_memory_gdl, &event_mem_root, - MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); - int error= 0; IO_CACHE *log_file= log->flip(); @@ -11578,13 +11572,9 @@ static int online_alter_read_from_binlog(THD *thd, rpl_group_info *rgi, break; ev->thd= thd; - thd->set_n_backup_active_arena(&event_arena, &backup_arena); error= ev->apply_event(rgi); - thd->restore_active_arena(&event_arena, &backup_arena); if (thd->is_error()) error= 1; - event_arena.free_items(); - free_root(&event_mem_root, MYF(MY_KEEP_PREALLOC)); if (ev != rgi->rli->relay_log.description_event_for_exec) delete ev; thd_progress_report(thd, my_b_tell(log_file), thd->progress.max_counter); diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 089f17515ef..d236f0b863f 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -627,8 +627,7 @@ bool THD::drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table) table->s->db.str, table->s->table_name.str)); // close all handlers in case it is statement abort and some can be left - if (is_error()) - table->file->ha_reset(); + table->file->ha_reset(); locked= lock_temporary_tables();