mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
Fix for bug #25044 "ALTER TABLE ... ENABLE KEYS acquires global 'opening
tables' lock." Execution of ALTER TABLE ... ENABLE KEYS on a table (which can take rather long time) prevented concurrent execution of all statements using tables. The problem was caused by the fact that we were holding LOCK_open mutex during whole duration of this statement and particularly during call to handler::enable_indexes(). This behavior was introduced as part of the fix for bug 14262 "SP: DROP PROCEDURE|VIEW (maybe more) write to binlog too late (race cond)" The patch simply restores old behavior. Note that we can safely do this as this operation takes exclusive lock (similar to name-lock) which blocks both DML and DDL on the table being altered. It also introduces mysql-test/include/wait_show_pattern.inc helper script which is used to make test-case for this bug robust enough.
This commit is contained in:
@@ -3146,19 +3146,30 @@ view_err:
|
||||
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
|
||||
!table->s->tmp_table) // no need to touch frm
|
||||
{
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
|
||||
switch (alter_info->keys_onoff) {
|
||||
case LEAVE_AS_IS:
|
||||
error= 0;
|
||||
break;
|
||||
case ENABLE:
|
||||
/*
|
||||
wait_while_table_is_used() ensures that table being altered is
|
||||
opened only by this thread and that TABLE::TABLE_SHARE::version
|
||||
of TABLE object corresponding to this table is 0.
|
||||
The latter guarantees that no DML statement will open this table
|
||||
until ALTER TABLE finishes (i.e. until close_thread_tables())
|
||||
while the fact that the table is still open gives us protection
|
||||
from concurrent DDL statements.
|
||||
*/
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
|
||||
/* COND_refresh will be signaled in close_thread_tables() */
|
||||
break;
|
||||
case DISABLE:
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
|
||||
/* COND_refresh will be signaled in close_thread_tables() */
|
||||
break;
|
||||
@@ -3171,6 +3182,16 @@ view_err:
|
||||
error= 0;
|
||||
}
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
/*
|
||||
Unlike to the above case close_cached_table() below will remove ALL
|
||||
instances of TABLE from table cache (it will also remove table lock
|
||||
held by this thread). So to make actual table renaming and writing
|
||||
to binlog atomic we have to put them into the same critical section
|
||||
protected by LOCK_open mutex. This also removes gap for races between
|
||||
access() and mysql_rename_table() calls.
|
||||
*/
|
||||
|
||||
if (!error && (new_name != table_name || new_db != db))
|
||||
{
|
||||
thd->proc_info="rename";
|
||||
|
||||
Reference in New Issue
Block a user