mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
Backport of:
---------------------------------------------------------- revno: 2630.10.1 committer: Konstantin Osipov <konstantin@mysql.com> branch nick: mysql-6.0-lock-tables-tidyup timestamp: Wed 2008-06-11 15:49:58 +0400 message: WL#3726, review fixes. Now that we have metadata locks, we don't need to keep a crippled TABLE instance in the table cache to indicate that a table is locked. Remove all code that used this technique. Instead, rely on metadata locks and use the standard open_table() and close_thread_table() to manipulate with the table cache tables. Removes a list of functions that have become unused (see the comment for sql_base.cc for details). Under LOCK TABLES, keep a TABLE_LIST instance for each table that may be temporarily closed. For that, implement an own class for LOCK TABLES mode, Locked_tables_list. This is a pre-requisite patch for WL#4144. This is not exactly a backport: there is no new online ALTER table in Celosia, so the old alter table code was changed to work with the new table cache API. mysql-test/r/lock.result: Update results (WL#3726 post-review patch). mysql-test/r/trigger-compat.result: We take the table from the table cache now, thus no warning. mysql-test/suite/rpl/r/rpl_trigger.result: We take the table from the table cache now, thus no warning. mysql-test/t/lock.test: Additional tests for LOCK TABLES mode (previously not covered by the test suite (WL#3726). sql/field.h: Remove reopen_table(). sql/lock.cc: Remove an obsolete parameter of mysql_lock_remove(). It's not used anywhere now either. sql/mysql_priv.h: Add 4 new open_table() flags. Remove declarations of removed functions. sql/sp_head.cc: Rename thd->mdl_el_root to thd->locked_tables_root. sql/sql_acl.cc: Use the new implementation of unlock_locked_tables(). sql/sql_base.cc: Implement class Locked_tables_list. Implement close_all_tables_for_name(). Rewrite close_cached_tables() to use the new reopen_tables(). Remove reopen_table(), reopen_tables(), reopen_table_entry() (ex. open_unireg_entry()), close_data_files_and_leave_as_placeholders(), close_handle_and_leave_table_as_placeholder(), close_cached_table(), table_def_change_share(), reattach_merge(), reopen_name_locked_table(), unlink_open_table(). Move acquisition of a metadata lock into an own function - open_table_get_mdl_lock(). sql/sql_class.cc: Deploy class Locked_tables_list. sql/sql_class.h: Declare class Locked_tables_list. Keep one instance of this class in class THD. Rename mdl_el_root to locked_tables_root. sql/sql_db.cc: Update a comment. sql/sql_insert.cc: Use the plain open_table() to open a just created table in CREATE TABLE .. SELECT. sql/sql_parse.cc: Use thd->locked_tables_list to enter and leave LTM_LOCK_TABLES mode. sql/sql_partition.cc: Deploy the new method of working with partitioned table locks. sql/sql_servers.cc: Update to the new signature of unlock_locked_tables(). sql/sql_table.cc: In mysql_rm_table_part2(), the branch that removes a table under LOCK TABLES, make sure that the table being dropped is also removed from THD::locked_tables_list. Update ALTER TABLE and CREATE TABLE LIKE implementation to use open_table() and close_all_tables_for_name() instead of reopen_tables(). sql/sql_trigger.cc: Use the new locking way. sql/table.h: Add TABLE::pos_in_locked_tables, which is used only under LOCK TABLES.
This commit is contained in:
161
sql/sql_table.cc
161
sql/sql_table.cc
@@ -1966,7 +1966,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
case -1:
|
||||
DBUG_ASSERT(thd->in_sub_stmt);
|
||||
error= 1;
|
||||
goto err_with_placeholders;
|
||||
goto err;
|
||||
default:
|
||||
// temporary table not found
|
||||
error= 0;
|
||||
@@ -2003,18 +2003,19 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
{
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
if (close_cached_table(thd, table->table))
|
||||
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
|
||||
{
|
||||
error= -1;
|
||||
goto err_with_placeholders;
|
||||
goto err;
|
||||
}
|
||||
close_all_tables_for_name(thd, table->table->s, TRUE);
|
||||
table->table= 0;
|
||||
}
|
||||
|
||||
if (thd->killed)
|
||||
{
|
||||
error= -1;
|
||||
goto err_with_placeholders;
|
||||
goto err;
|
||||
}
|
||||
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
|
||||
/* remove .frm file and engine files */
|
||||
@@ -2178,7 +2179,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
*/
|
||||
}
|
||||
}
|
||||
err_with_placeholders:
|
||||
err:
|
||||
if (!drop_temporary)
|
||||
{
|
||||
/*
|
||||
@@ -2195,7 +2196,7 @@ err_with_placeholders:
|
||||
if (thd->locked_tables_mode &&
|
||||
thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
|
||||
{
|
||||
unlock_locked_tables(thd);
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
goto end;
|
||||
}
|
||||
for (table= tables; table; table= table->next_local)
|
||||
@@ -4315,6 +4316,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
|
||||
HA_CHECK_OPT *check_opt)
|
||||
{
|
||||
MDL_LOCK_DATA *mdl_lock_data= 0;
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
DBUG_ENTER("prepare_for_restore");
|
||||
|
||||
if (table->table) // do not overwrite existing tables on restore
|
||||
@@ -4360,16 +4362,16 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
|
||||
DBUG_RETURN(send_check_errmsg(thd, table, "restore",
|
||||
"Failed generating table from .frm file"));
|
||||
}
|
||||
table->mdl_lock_data= mdl_lock_data;
|
||||
}
|
||||
|
||||
/*
|
||||
Now we should be able to open the partially restored table
|
||||
to finish the restore in the handler later on
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, table))
|
||||
if (open_table(thd, table, thd->mem_root,
|
||||
&ot_action_unused, MYSQL_OPEN_REOPEN))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (mdl_lock_data)
|
||||
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
|
||||
DBUG_RETURN(send_check_errmsg(thd, table, "restore",
|
||||
@@ -4377,7 +4379,6 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
|
||||
}
|
||||
/* A MERGE table must not come here. */
|
||||
DBUG_ASSERT(!table->table || !table->table->child_l);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@@ -4392,7 +4393,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
const char **ext;
|
||||
MY_STAT stat_info;
|
||||
MDL_LOCK_DATA *mdl_lock_data;
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
DBUG_ENTER("prepare_for_repair");
|
||||
uint reopen_for_repair_flags= (MYSQL_LOCK_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_HAS_MDL_LOCK);
|
||||
|
||||
if (!(check_opt->sql_flags & TT_USEFRM))
|
||||
DBUG_RETURN(0);
|
||||
@@ -4428,8 +4432,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0); // Out of memory
|
||||
}
|
||||
table= &tmp_table;
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
table= &tmp_table;
|
||||
table_list->mdl_lock_data= mdl_lock_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4490,8 +4495,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
Table was successfully open in mysql_admin_table(). Now we need
|
||||
to close it, but leave it protected by exclusive metadata lock.
|
||||
*/
|
||||
if (close_cached_table(thd, table))
|
||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||
goto end;
|
||||
close_all_tables_for_name(thd, table_list->table->s, FALSE);
|
||||
table_list->table= 0;
|
||||
}
|
||||
/*
|
||||
@@ -4519,21 +4525,23 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (thd->locked_tables_list.reopen_tables(thd))
|
||||
goto end;
|
||||
|
||||
/*
|
||||
Now we should be able to open the partially repaired table
|
||||
to finish the repair in the handler later on.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, table_list))
|
||||
if (open_table(thd, table_list, thd->mem_root,
|
||||
&ot_action_unused, reopen_for_repair_flags))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
error= send_check_errmsg(thd, table_list, "repair",
|
||||
"Failed to open partially repaired table");
|
||||
goto end;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
end:
|
||||
thd->locked_tables_list.unlink_all_closed_tables();
|
||||
if (table == &tmp_table)
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
@@ -5334,6 +5342,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
db, table_name, reg_ext, 0);
|
||||
if (!access(dst_path, F_OK))
|
||||
goto table_exists;
|
||||
/*
|
||||
Make the metadata lock available to open_table() called to
|
||||
reopen the table down the road.
|
||||
*/
|
||||
table->mdl_lock_data= target_lock_data;
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
|
||||
@@ -5463,20 +5476,16 @@ binlog:
|
||||
char buf[2048];
|
||||
String query(buf, sizeof(buf), system_charset_info);
|
||||
query.length(0); // Have to zero it since constructor doesn't
|
||||
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
/*
|
||||
Here we open the destination table, on which we already have
|
||||
exclusive metada lock. This is needed for store_create_info()
|
||||
to work. The table will be closed by unlink_open_table() at
|
||||
the end of this function.
|
||||
exclusive metadata lock. This is needed for store_create_info()
|
||||
to work. The table will be closed by close_thread_table() at
|
||||
the end of this branch.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, table))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (open_table(thd, table, thd->mem_root, &ot_action_unused,
|
||||
MYSQL_OPEN_REOPEN))
|
||||
goto err;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
int result __attribute__((unused))=
|
||||
store_create_info(thd, table, &query,
|
||||
@@ -5485,8 +5494,14 @@ binlog:
|
||||
DBUG_ASSERT(result == 0); // store_create_info() always return 0
|
||||
write_bin_log(thd, TRUE, query.ptr(), query.length());
|
||||
|
||||
DBUG_ASSERT(thd->open_tables == table->table);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlink_open_table(thd, table->table, FALSE);
|
||||
/*
|
||||
When opening the table, we ignored the locked tables
|
||||
(MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
|
||||
risking to close some locked table.
|
||||
*/
|
||||
close_thread_table(thd, &thd->open_tables);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
else // Case 1
|
||||
@@ -6789,13 +6804,14 @@ view_err:
|
||||
/*
|
||||
Then do a 'simple' rename of the table. First we need to close all
|
||||
instances of 'source' table.
|
||||
Note that if close_cached_table() returns error here (i.e. if
|
||||
Note that if wait_while_table_is_used() returns error here (i.e. if
|
||||
this thread was killed) then it must be that previous step of
|
||||
simple rename did nothing and therefore we can safely reture
|
||||
simple rename did nothing and therefore we can safely return
|
||||
without additional clean-up.
|
||||
*/
|
||||
if (close_cached_table(thd, table))
|
||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||
goto err;
|
||||
close_all_tables_for_name(thd, table->s, TRUE);
|
||||
/*
|
||||
Then, we want check once again that target table does not exist.
|
||||
Actually the order of these two steps does not matter since
|
||||
@@ -7384,11 +7400,12 @@ view_err:
|
||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
|
||||
goto err_new_table_cleanup;
|
||||
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
|
||||
close_data_files_and_leave_as_placeholders(thd, db, table_name);
|
||||
close_all_tables_for_name(thd, table->s,
|
||||
new_name != table_name || new_db != db);
|
||||
|
||||
error=0;
|
||||
table_list->table= table= 0; /* Safety */
|
||||
save_old_db_type= old_db_type;
|
||||
|
||||
/*
|
||||
@@ -7410,6 +7427,7 @@ view_err:
|
||||
/* This type cannot happen in regular ALTER. */
|
||||
new_db_type= old_db_type= NULL;
|
||||
}
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
|
||||
FN_TO_IS_TMP))
|
||||
{
|
||||
@@ -7433,10 +7451,15 @@ view_err:
|
||||
FN_FROM_IS_TMP);
|
||||
}
|
||||
|
||||
if (! error)
|
||||
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
|
||||
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
if (error)
|
||||
{
|
||||
/* This shouldn't happen. But let us play it safe. */
|
||||
goto err_with_placeholders;
|
||||
goto err_with_mdl;
|
||||
}
|
||||
|
||||
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
||||
@@ -7446,6 +7469,7 @@ view_err:
|
||||
To do this we need to obtain a handler object for it.
|
||||
NO need to tamper with MERGE tables. The real open is done later.
|
||||
*/
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
TABLE *t_table;
|
||||
if (new_name != table_name || new_db != db)
|
||||
{
|
||||
@@ -7454,51 +7478,39 @@ view_err:
|
||||
table_list->table_name_length= strlen(new_name);
|
||||
table_list->db= new_db;
|
||||
table_list->db_length= strlen(new_db);
|
||||
if (reopen_name_locked_table(thd, table_list))
|
||||
goto err_with_placeholders;
|
||||
t_table= table_list->table;
|
||||
table_list->mdl_lock_data= target_lock_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reopen_table(table))
|
||||
goto err_with_placeholders;
|
||||
t_table= table;
|
||||
/*
|
||||
Under LOCK TABLES, we have a different mdl_lock_data
|
||||
points to a different instance than the one set initially
|
||||
to request the lock.
|
||||
*/
|
||||
table_list->mdl_lock_data= mdl_lock_data;
|
||||
}
|
||||
/* Tell the handler that a new frm file is in place. */
|
||||
if (t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
|
||||
create_info))
|
||||
goto err_with_placeholders;
|
||||
if (thd->locked_tables_mode)
|
||||
if (open_table(thd, table_list, thd->mem_root,
|
||||
&ot_action_unused, MYSQL_OPEN_REOPEN))
|
||||
{
|
||||
if (new_name == table_name && new_db == db)
|
||||
{
|
||||
/*
|
||||
We are going to reopen table down on the road, so we have to restore
|
||||
state of the TABLE object which we used for obtaining of handler
|
||||
object to make it suitable for reopening.
|
||||
*/
|
||||
DBUG_ASSERT(t_table == table);
|
||||
close_handle_and_leave_table_as_placeholder(table);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unlink the new name from the list of locked tables. */
|
||||
unlink_open_table(thd, t_table, FALSE);
|
||||
}
|
||||
goto err_with_mdl;
|
||||
}
|
||||
}
|
||||
t_table= table_list->table;
|
||||
|
||||
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
|
||||
/* Tell the handler that a new frm file is in place. */
|
||||
error= t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
|
||||
create_info);
|
||||
|
||||
DBUG_ASSERT(thd->open_tables == t_table);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
close_thread_table(thd, &thd->open_tables);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
table_list->table= 0;
|
||||
|
||||
if (thd->locked_tables_mode && new_name == table_name && new_db == db)
|
||||
{
|
||||
thd->in_lock_tables= 1;
|
||||
error= reopen_tables(thd, 1);
|
||||
thd->in_lock_tables= 0;
|
||||
if (error)
|
||||
goto err_with_placeholders;
|
||||
goto err_with_mdl;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (thd->locked_tables_list.reopen_tables(thd))
|
||||
goto err_with_mdl;
|
||||
|
||||
thd_proc_info(thd, "end");
|
||||
|
||||
@@ -7541,9 +7553,6 @@ view_err:
|
||||
{
|
||||
if ((new_name != table_name || new_db != db))
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlink_open_table(thd, table, FALSE);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
|
||||
}
|
||||
@@ -7607,14 +7616,14 @@ err:
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
err_with_placeholders:
|
||||
err_with_mdl:
|
||||
/*
|
||||
An error happened while we were holding exclusive name metadata lock
|
||||
on table being altered. To be safe under LOCK TABLES we should remove
|
||||
placeholders from the list of open tables and relese metadata lock.
|
||||
on table being altered. To be safe under LOCK TABLES we should
|
||||
remove all references to the altered table from the list of locked
|
||||
tables and release the exclusive metadata lock.
|
||||
*/
|
||||
unlink_open_table(thd, table, FALSE);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
thd->locked_tables_list.unlink_all_closed_tables();
|
||||
if (target_lock_data)
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
|
||||
|
||||
Reference in New Issue
Block a user