Commit 50095046 authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-32614 LeakSanitizer errors in copy_data_between_tables

The memory leak occurs on error when backup_reset_alter_copy_lock fails
with timeout. This leads to the alter rollback, but flush_unused is not
called.

Move table flushing on error handling to a single place and mind more
possible failures this time.
parent c2e16b3a
......@@ -1807,6 +1807,28 @@ a b
456 NULL
789 NULL
drop table t1;
# MDEV-32614 LeakSanitizer errors in copy_data_between_tables
create table t (a int, b int) engine=aria;
insert into t select seq, seq from seq_1_to_5;
backup stage start;
connect con_lock,localhost,root,,;
set lock_wait_timeout= 1;
set debug_sync='copy_data_between_tables_before_reset_backup_lock wait_for continue';
alter table t add index (b), algorithm=copy, lock=none;
connection default;
backup stage block_commit;
set debug_sync='now signal continue';
connection con_lock;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
set debug_sync='copy_data_between_tables_before_reset_backup_lock wait_for continue';
alter table t add index (a), algorithm=copy, lock=none;
connection default;
backup stage end;
set debug_sync='now signal continue';
connection con_lock;
disconnect con_lock;
connection default;
drop table t;
set global default_storage_engine= MyISAM;
disconnect con1;
disconnect con2;
......
......@@ -2066,6 +2066,41 @@ select * from t1;
drop table t1;
--echo # MDEV-32614 LeakSanitizer errors in copy_data_between_tables
create table t (a int, b int) engine=aria;
insert into t select seq, seq from seq_1_to_5;
backup stage start;
--connect (con_lock,localhost,root,,)
set lock_wait_timeout= 1;
set debug_sync='copy_data_between_tables_before_reset_backup_lock wait_for continue';
send alter table t add index (b), algorithm=copy, lock=none;
--connection default
backup stage block_commit;
set debug_sync='now signal continue';
--connection con_lock
--error ER_LOCK_WAIT_TIMEOUT
--reap
# --echo # error $mysql_errno
set debug_sync='copy_data_between_tables_before_reset_backup_lock wait_for continue';
send alter table t add index (a), algorithm=copy, lock=none;
--connection default
backup stage end;
set debug_sync='now signal continue';
--connection con_lock
--reap
--disconnect con_lock
--connection default
drop table t;
eval set global default_storage_engine= $default_storage_engine;
--disconnect con1
......
......@@ -12130,6 +12130,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
#ifdef HAVE_REPLICATION
if (online)
{
DBUG_ASSERT(from->s->online_alter_binlog == NULL);
from->s->online_alter_binlog= new Cache_flip_event_log();
if (!from->s->online_alter_binlog)
goto err;
......@@ -12363,13 +12364,26 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
thd_progress_next_stage(thd);
error= online_alter_read_from_binlog(thd, &rgi, binlog, &found_count);
}
if (error)
from->s->tdc->flush_unused(1); // to free the binlog
to->pos_in_table_list= NULL; // Safety
DBUG_ASSERT(thd->lex->sql_command == saved_sql_command);
thd->lex->sql_command= saved_sql_command; // Just in case
}
else if (online) // error was on copy stage
#endif
if (error > 0 && !from->s->tmp_table)
{
/* We are going to drop the temporary table */
to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
}
DEBUG_SYNC(thd, "copy_data_between_tables_before_reset_backup_lock");
if (backup_reset_alter_copy_lock(thd))
error= 1;
if (unlikely(mysql_trans_commit_alter_copy_data(thd)))
error= 1;
if (unlikely(error) && online)
{
/*
We can't free the resources properly now, as we can still be in
......@@ -12383,24 +12397,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
If share exists, we'll always have ref_count >= 1.
Once it reaches destroy(), nobody can acquire it again,
therefore, only release() is possible at this moment.
Also, this will release the binlog.
*/
from->s->tdc->flush_unused(1); // to free the binlog
}
#endif
if (error > 0 && !from->s->tmp_table)
{
/* We are going to drop the temporary table */
to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
from->s->tdc->flush_unused(1);
}
DEBUG_SYNC(thd, "copy_data_between_tables_before_reset_backup_lock");
if (backup_reset_alter_copy_lock(thd))
error= 1;
if (unlikely(mysql_trans_commit_alter_copy_data(thd)))
error= 1;
err:
if (bulk_insert_started)
(void) to->file->ha_end_bulk_insert();
......
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