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.
mysql-test/include/wait_slave_status.inc:
Now wait_slave_status.inc reuses more generic wait_output_matches.inc script.
sql/sql_table.cc:
mysql_alter_table():
Changed ALTER TABLE ... ENABLE/DISABLE KEYS not to hold LOCK_open mutex
during call to handler::enable_indexes() as the latter can take rather
long time and therefore such ALTER would block execution of all other
statements that use tables. We can safely do this as this operation takes
exclusive lock (similar to name-lock) on the table which is altered.
mysql-test/include/wait_show_pattern.inc:
New BitKeeper file ``mysql-test/include/wait_show_pattern.inc''
mysql-test/r/alter_table-big.result:
New BitKeeper file ``mysql-test/r/alter_table-big.result''
mysql-test/t/alter_table-big.test:
New BitKeeper file ``mysql-test/t/alter_table-big.test''
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