mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
A fix for Bug#41158 "DROP TABLE holds LOCK_open during unlink()".
Remove acquisition of LOCK_open around file system operations, since such operations are now protected by metadata locks. Rework table discovery algorithm to not require LOCK_open. No new tests added since all MDL locking operations are covered in lock.test and mdl_sync.test, and as long as these tests pass despite the increased concurrency, consistency must be unaffected. mysql-test/t/disabled.def: Disable NDB tests due to Bug#55799. sql/datadict.cc: No longer necessary to protect ha_create_table() with LOCK_open. Serial execution is now ensured by metadata locks. sql/ha_ndbcluster.cc: Do not manipulate with LOCK_open in cluster code. sql/ha_ndbcluster_binlog.cc: Do not manipulate with LOCK_open in cluster code. sql/ha_ndbcluster_binlog.h: Update function signature. sql/handler.cc: Implement ha_check_if_table_exists(). @todo: some engines provide ha_table_exists_in_engine() handlerton call, for those we perhaps shouldn't call ha_discover(), to be more efficient. Since currently it's only NDB, postpone till integration with NDB. sql/handler.h: Declare ha_check_if_table_exists() function. sql/mdl.cc: Remove an obsolete comment. sql/sql_base.cc: Update to a new signature of close_cached_tables(): from now on we always call it without LOCK_open. Update comments. Remove get_table_share_with_create(), we should not attempt to create a table under LOCK_open. Introduce get_table_share_with_discover() instead, which would request a back off action if the table exists in engine. Remove acquisition of LOCK_open for data dictionary operations, such as check_if_table_exists(). Do not use get_table_share_with_create/discover for views, where it's not needed. Make tdc_remove_table() optionally acquire LOCK_open to simplify usage of this function. Use the right mutex in the partitioning code when manipulating with thd->open_tables. sql/sql_base.h: Update signatures of changes functions. sql/sql_insert.cc: Do not wrap quick_rm_table() with LOCK_open acquisition, this is unnecessary. sql/sql_parse.cc: Update to the new calling convention of tdc_remove_table(). Update to the new signature of close_cached_tables(). Update comments. sql/sql_rename.cc: Update to the new calling convention of tdc_remove_table(). Remove acquisition of LOCK_open around filesystem operations. sql/sql_show.cc: Remove get_trigger_table_impl(). Do not acquire LOCK_open for a dirty read of the trigger file. sql/sql_table.cc: Do not acquire LOCK_open for filesystem operations. sql/sql_trigger.cc: Do not require LOCK_open for trigger file I/O. sql/sql_truncate.cc: Update to the new signature of tdc_remove_table(). sql/sql_view.cc: Do not require LOCK_open for view I/O. Use tdc_remove_table() to expel view share. Update comments. sql/sys_vars.cc: Update to the new signature of close_cached_tables().
This commit is contained in:
@@ -1723,7 +1723,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
|
||||
completing this we write a new phase to the log entry that will
|
||||
deactivate it.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
lpt->table->file->ha_create_handler_files(path, shadow_path,
|
||||
@@ -1779,7 +1778,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
|
||||
#endif
|
||||
|
||||
err:
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
|
||||
part_info->frm_log_entry= NULL;
|
||||
@@ -1955,10 +1953,11 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
|
||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
||||
DBUG_RETURN(1);
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
for (table= tables; table; table= table->next_local)
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
{
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2104,14 +2103,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
table->internal_tmp_table ?
|
||||
FN_IS_TMP : 0);
|
||||
}
|
||||
/*
|
||||
TODO: Investigate what should be done to remove this lock completely.
|
||||
Is exclusive meta-data lock enough ?
|
||||
*/
|
||||
DEBUG_SYNC(thd, "rm_table_part2_before_delete_table");
|
||||
DBUG_EXECUTE_IF("sleep_before_part2_delete_table",
|
||||
my_sleep(100000););
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (drop_temporary ||
|
||||
((access(path, F_OK) &&
|
||||
ha_create_table_from_engine(thd, db, alias)) ||
|
||||
@@ -2131,8 +2125,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
char *end;
|
||||
/*
|
||||
Cannot use the db_type from the table, since that might have changed
|
||||
while waiting for the exclusive name lock. We are under LOCK_open,
|
||||
so reading from the frm-file is safe.
|
||||
while waiting for the exclusive name lock.
|
||||
*/
|
||||
if (frm_db_type == DB_TYPE_UNKNOWN)
|
||||
{
|
||||
@@ -2173,7 +2166,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
error|= new_error;
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
if (error)
|
||||
{
|
||||
if (wrong_tables.length())
|
||||
@@ -4053,7 +4045,6 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
goto err;
|
||||
}
|
||||
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
if (!access(path,F_OK))
|
||||
@@ -4061,7 +4052,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
goto warn;
|
||||
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
We don't assert here, but check the result, because the table could be
|
||||
@@ -4071,11 +4062,14 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
Then she could create the table. This case is pretty obscure and
|
||||
therefore we don't introduce a new error message only for it.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (get_cached_table_share(db, table_name))
|
||||
{
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4083,7 +4077,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
exist in any storage engine. In such a case it should
|
||||
be discovered and the error ER_TABLE_EXISTS_ERROR be returned
|
||||
unless user specified CREATE TABLE IF EXISTS
|
||||
The LOCK_open mutex has been locked to make sure no
|
||||
An exclusive metadata lock ensures that no
|
||||
one else is attempting to discover the table. Since
|
||||
it's not on disk as a frm file, no one could be using it!
|
||||
*/
|
||||
@@ -4104,12 +4098,12 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
if (create_if_not_exists)
|
||||
goto warn;
|
||||
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
DBUG_PRINT("info", ("error: %u from storage engine", retcode));
|
||||
my_error(retcode, MYF(0),table_name);
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4142,7 +4136,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
if (test_if_data_home_dir(dirpath))
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (create_info->index_file_name)
|
||||
@@ -4151,7 +4145,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
if (test_if_data_home_dir(dirpath))
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4159,7 +4153,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
if (check_partition_dirs(thd->lex->part_info))
|
||||
{
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|
||||
|
||||
@@ -4182,7 +4176,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
if (rea_create_table(thd, path, db, table_name,
|
||||
create_info, alter_info->create_list,
|
||||
key_count, key_info_buffer, file))
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
|
||||
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
{
|
||||
@@ -4190,15 +4184,12 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
if (!(open_temporary_table(thd, path, db, table_name, 1)))
|
||||
{
|
||||
(void) rm_temporary_table(create_info->db_type, path);
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
thd->thread_specific_used= TRUE;
|
||||
}
|
||||
|
||||
error= FALSE;
|
||||
unlock_and_end:
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
|
||||
err:
|
||||
thd_proc_info(thd, "After create");
|
||||
delete file;
|
||||
@@ -4210,7 +4201,7 @@ warn:
|
||||
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
|
||||
alias);
|
||||
create_info->table_existed= 1; // Mark that table existed
|
||||
goto unlock_and_end;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
@@ -4459,20 +4450,19 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
|
||||
hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (!(share= (get_table_share(thd, table_list, key, key_length, 0,
|
||||
&error, hash_value))))
|
||||
{
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
share= get_table_share(thd, table_list, key, key_length, 0,
|
||||
&error, hash_value);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
if (share == NULL)
|
||||
DBUG_RETURN(0); // Can't open frm file
|
||||
}
|
||||
|
||||
if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
release_table_share(share);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0); // Out of memory
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
table= &tmp_table;
|
||||
}
|
||||
|
||||
@@ -5136,10 +5126,8 @@ send_result_message:
|
||||
}
|
||||
else if (open_for_modify || fatal_error)
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
||||
table->db, table->table_name);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
table->db, table->table_name, FALSE);
|
||||
/*
|
||||
May be something modified. Consequently, we have to
|
||||
invalidate the query cache.
|
||||
@@ -6775,7 +6763,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
else
|
||||
{
|
||||
*fn_ext(new_name)=0;
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
|
||||
error= -1;
|
||||
else if (Table_triggers_list::change_table_name(thd, db, table_name,
|
||||
@@ -6785,7 +6772,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
table_name, 0);
|
||||
error= -1;
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7404,7 +7390,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
/* This type cannot happen in regular ALTER. */
|
||||
new_db_type= old_db_type= NULL;
|
||||
}
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
|
||||
FN_TO_IS_TMP))
|
||||
{
|
||||
@@ -7431,8 +7416,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
if (! error)
|
||||
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
|
||||
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
|
||||
if (error)
|
||||
{
|
||||
/* This shouldn't happen. But let us play it safe. */
|
||||
|
||||
Reference in New Issue
Block a user