1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Bug#54747: Deadlock between REORGANIZE PARTITION and SELECT is not detected

The ALTER PARTITION and SELECT seemed to be deadlocked
when having innodb_thread_concurrency = 1.

Problem was that there was unreleased latches
in the ALTER PARTITION thread which was needed
by the SELECT thread to be able to continue.

Solution was to release the latches by commit 
before requesting upgrade to exclusive MDL lock.

Updated according to reviewers comments (3).

mysql-test/r/partition_innodb.result:
  updated test result
mysql-test/t/partition_innodb.test:
  added test
sql/sql_partition.cc:
  Moved implicit commit into mysql_change_partition
  so that if latches are taken, they are always released
  before waiting on exclusive lock.
sql/sql_table.cc:
  refactored the code to prepare and commit
  around copy_data_between_tables, to be able
  to reuse it in mysql_change_partitions
sql/sql_table.h:
  exporting mysql_trans_prepare/commit_alter_copy_data
This commit is contained in:
Mattias Jonsson
2010-08-20 19:15:48 +02:00
parent f4cef8d31f
commit 8df0bf13ab
5 changed files with 156 additions and 31 deletions

View File

@@ -6740,6 +6740,54 @@ err_with_mdl:
}
/* mysql_alter_table */
/**
Prepare the transaction for the alter table's copy phase.
*/
bool mysql_trans_prepare_alter_copy_data(THD *thd)
{
DBUG_ENTER("mysql_prepare_alter_copy_data");
/*
Turn off recovery logging since rollback of an alter table is to
delete the new table so there is no need to log the changes to it.
This needs to be done before external_lock.
*/
if (ha_enable_transaction(thd, FALSE))
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
}
/**
Commit the copy phase of the alter table.
*/
bool mysql_trans_commit_alter_copy_data(THD *thd)
{
bool error= FALSE;
DBUG_ENTER("mysql_commit_alter_copy_data");
if (ha_enable_transaction(thd, TRUE))
DBUG_RETURN(TRUE);
/*
Ensure that the new table is saved properly to disk before installing
the new .frm.
And that InnoDB's internal latches are released, to avoid deadlock
when waiting on other instances of the table before rename (Bug#54747).
*/
if (trans_commit_stmt(thd))
error= TRUE;
if (trans_commit_implicit(thd))
error= TRUE;
DBUG_RETURN(error);
}
static int
copy_data_between_tables(TABLE *from,TABLE *to,
List<Create_field> &create,
@@ -6766,14 +6814,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
ulonglong prev_insert_id;
DBUG_ENTER("copy_data_between_tables");
/*
Turn off recovery logging since rollback of an alter table is to
delete the new table so there is no need to log the changes to it.
This needs to be done before external_lock
*/
error= ha_enable_transaction(thd, FALSE);
if (error)
if (mysql_trans_prepare_alter_copy_data(thd))
DBUG_RETURN(-1);
if (!(copy= new Copy_field[to->s->fields]))
@@ -6932,20 +6973,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
}
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (ha_enable_transaction(thd, TRUE))
{
if (mysql_trans_commit_alter_copy_data(thd))
error= 1;
goto err;
}
/*
Ensure that the new table is saved properly to disk so that we
can do a rename
*/
if (trans_commit_stmt(thd))
error=1;
if (trans_commit_implicit(thd))
error=1;
err:
thd->variables.sql_mode= save_sql_mode;