#At file:///home/dlenev/src/bzr/mysql-6.1-mil14/ based on revid:kostja@stripped
2734 Dmitry Lenev 2009-05-18
WL#148 "Foreign keys".
Milestone 14 "DDL checks and changes: DROP, TRUNCATE, RENAME".
Tentative patch that tries to get rid of per-execution MDL request
allocation by introducing per-table per-execution context for DROP
TABLE operation.
modified:
sql/ha_ndbcluster.cc
sql/sql_db.cc
sql/sql_table.cc
sql/table.h
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2009-04-22 22:12:25 +0000
+++ b/sql/ha_ndbcluster.cc 2009-05-18 11:37:41 +0000
@@ -7597,9 +7597,12 @@ int ndbcluster_find_files(handlerton *ht
DBUG_PRINT("info", ("Remove table %s/%s", db, file_name_str));
// Delete the table and all related files
TABLE_LIST table_list;
+ MDL_request mdl_request;
bzero((char*) &table_list,sizeof(table_list));
table_list.db= (char*) db;
table_list.alias= table_list.table_name= (char*)file_name_str;
+ mdl_request.init(0, db, file_name_str);
+ table_list.mdl_request= &mdl_request;
/*
set TNO_NO_NDB_DROP_TABLE flag to not drop ndb table.
it should not exist anyways
=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc 2009-05-05 12:58:43 +0000
+++ b/sql/sql_db.cc 2009-05-18 11:37:41 +0000
@@ -1162,6 +1162,9 @@ static long mysql_rm_known_files(THD *th
table_list->alias= table_list->table_name; // If lower_case_table_names=2
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
+ table_list->mdl_request= MDL_request::create(0, table_list->db,
+ table_list->table_name,
+ thd->mem_root);
/* Link into list */
(*tot_list_next)= table_list;
tot_list_next= &table_list->next_local;
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2009-05-15 12:46:44 +0000
+++ b/sql/sql_table.cc 2009-05-18 11:37:41 +0000
@@ -1710,6 +1710,25 @@ static bool fk_drop_table_add_parent_tab
/**
+ Context carrying information about table being dropped for the whole
+ duration of DROP TABLE/DROP DATABASE operation.
+*/
+
+class Drop_table_rcontext: public Sql_alloc
+{
+public:
+
+ Drop_table_rcontext(TABLE_LIST *table_arg)
+ : table(table_arg), table_type(NULL), is_temporary(FALSE)
+ {}
+
+ TABLE_LIST *table;
+ handlerton *table_type;
+ bool is_temporary;
+};
+
+
+/**
Runtime context for changes performed by DDL statement on a table
which participates in foreign key constraints.
@@ -1729,7 +1748,7 @@ public:
{
}
bool prepare_drop_table(TABLE_LIST *drop_table,
- TABLE_LIST *all_dropped_tables,
+ List<Drop_table_rcontext> &all_dropped_tables,
TABLE_LIST *all_parent_tables);
bool prepare_create_table(TABLE_LIST *create_table,
TABLE_LIST *fkey_tables,
@@ -1827,6 +1846,29 @@ handle_condition(THD *thd, uint sql_errn
/**
+ Find context for particular table in a list of Drop_table_rcontext contexts.
+*/
+
+static
+Drop_table_rcontext *find_table_in_list(List<Drop_table_rcontext> &list,
+ const char *db_name,
+ const char *table_name)
+{
+ List_iterator<Drop_table_rcontext> drop_rctx_it(list);
+ Drop_table_rcontext *drop_rctx;
+
+ while ((drop_rctx= drop_rctx_it++))
+ {
+ if (! drop_rctx->is_temporary &&
+ ! strcmp(drop_rctx->table->db, db_name) &&
+ ! strcmp(drop_rctx->table->table_name, table_name))
+ break;
+ }
+ return drop_rctx;
+}
+
+
+/**
Prepare context for drop table operation by preparing Parent_info
objects describing related tables from which foreign keys involving
table being dropped were removed.
@@ -1840,10 +1882,10 @@ handle_condition(THD *thd, uint sql_errn
@retval TRUE Failure (e.g. OOM or absence of one of the parent tables).
*/
-bool
-Foreign_key_ddl_rcontext::prepare_drop_table(TABLE_LIST *drop_table,
- TABLE_LIST *all_dropped_tables,
- TABLE_LIST *all_parent_tables)
+bool Foreign_key_ddl_rcontext::
+prepare_drop_table(TABLE_LIST *drop_table,
+ List<Drop_table_rcontext> &all_dropped_tables,
+ TABLE_LIST *all_parent_tables)
{
TABLE_SHARE *share;
char key[MAX_DBKEY_LENGTH];
@@ -1852,6 +1894,7 @@ Foreign_key_ddl_rcontext::prepare_drop_t
int error;
List_iterator<TABLE_LIST> tab_it(m_related_tables);
TABLE_LIST *tab;
+ Drop_table_rcontext *drop_rctx;
Foreign_key_name *name;
DBUG_ASSERT(m_drop);
@@ -1913,7 +1956,7 @@ Foreign_key_ddl_rcontext::prepare_drop_t
if (! tab)
{
- tab= find_table_in_local_list(all_dropped_tables,
+ drop_rctx= find_table_in_list(all_dropped_tables,
fk_s->parent_table_db.str,
fk_s->parent_table_name.str);
@@ -1922,7 +1965,9 @@ Foreign_key_ddl_rcontext::prepare_drop_t
is a temporary table which shadows it and gets dropped instead of it)
it must present among additionally locked tables.
*/
- if (! tab || ! tab->mdl_request)
+ if (drop_rctx)
+ tab= drop_rctx->table;
+ else
tab= find_table_in_local_list(all_parent_tables,
fk_s->parent_table_db.str,
fk_s->parent_table_name.str);
@@ -1977,11 +2022,13 @@ Foreign_key_ddl_rcontext::prepare_drop_t
break;
if (! tab)
{
- tab= find_table_in_local_list(all_dropped_tables,
+ drop_rctx= find_table_in_list(all_dropped_tables,
fk_s_p->child_table_db.str,
fk_s_p->child_table_name.str);
- if (! tab || ! tab->mdl_request)
+ if (drop_rctx)
+ tab= drop_rctx->table;
+ else
tab= find_table_in_local_list(all_parent_tables,
fk_s_p->child_table_db.str,
fk_s_p->child_table_name.str);
@@ -2119,34 +2166,23 @@ Foreign_key_ddl_rcontext::prepare_drop_t
static bool
lock_dropped_and_parent_tables(THD *thd,
- TABLE_LIST *tables, TABLE_LIST *parents,
+ List<Drop_table_rcontext> &tables,
+ TABLE_LIST *parents,
List<Foreign_key_name> &fk_names)
{
TABLE_LIST *table;
MDL_request *mdl_request;
+ List_iterator<Drop_table_rcontext> drop_rctx_it(tables);
+ Drop_table_rcontext *drop_rctx;
List_iterator<Foreign_key_name> fk_names_it(fk_names);
Foreign_key_name *fk_name;
- for (table= tables; table; table= table->next_local)
+ while ((drop_rctx= drop_rctx_it++))
{
- if (! table->table)
+ if (! drop_rctx->is_temporary)
{
- /*
- QQ: Ideally we should get rid of allocation here. But this can be
- problematic due to fact that we set TABLE_LIST::mdl_lock_data
- to 0 for temporary tables and rely on that (think of
- re-execution). Any other ideas?
- */
- if (! (mdl_request= MDL_request::create(0, table->db,
- table->table_name,
- thd->mem_root)))
- {
- thd->mdl_context.remove_all_requests();
- return TRUE;
- }
- mdl_request->set_type(MDL_EXCLUSIVE);
- thd->mdl_context.add_request(mdl_request);
- table->mdl_request= mdl_request;
+ drop_rctx->table->mdl_request->set_type(MDL_EXCLUSIVE);
+ thd->mdl_context.add_request(drop_rctx->table->mdl_request);
}
}
@@ -2188,20 +2224,23 @@ lock_dropped_and_parent_tables(THD *thd,
static bool
upgrade_mdl_for_dropped_and_parent_tables(THD *thd,
- TABLE_LIST *tables,
+ List<Drop_table_rcontext> &tables,
TABLE_LIST *parents,
List<Foreign_key_name> &fk_names)
{
+ List_iterator<Drop_table_rcontext> drop_rctx_it(tables);
+ Drop_table_rcontext *drop_rctx;
List_iterator<Foreign_key_name> fk_name_it(fk_names);
Foreign_key_name *fk_name;
TABLE_LIST *table;
/* Upgrade meta-data locks for all tables to be dropped. */
- for (table= tables; table; table= table->next_local)
+ while ((drop_rctx= drop_rctx_it++))
{
- if (table->table->s->tmp_table == NO_TMP_TABLE)
+ if (! drop_rctx->is_temporary)
{
- if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
+ if (wait_while_table_is_used(thd, drop_rctx->table->table,
+ HA_EXTRA_FORCE_REOPEN))
{
/*
QQ: Isn't it better to to downgrade locks before returning an error ?
@@ -2216,7 +2255,7 @@ upgrade_mdl_for_dropped_and_parent_table
get crashes due to query cache and foreign key handling code
accessing memory occupied by invalidated TABLE instances.
*/
- table->table= 0;
+ drop_rctx->table->table= 0;
}
}
@@ -2271,27 +2310,29 @@ upgrade_mdl_for_dropped_and_parent_table
*/
static bool
-fk_check_tables_before_drop(THD *thd, TABLE_LIST *tables,
+fk_check_tables_before_drop(THD *thd,
+ List<Drop_table_rcontext> tables,
TABLE_LIST **parents_to_lock,
List<Foreign_key_name> *fk_names_to_lock,
bool *has_not_locked_parent_or_fk_name)
{
- TABLE_LIST *table;
TABLE_SHARE *share;
char key[MAX_DBKEY_LENGTH];
uint key_length;
Silence_non_fatal_non_transient_error non_fatal_error_silencer;
int error;
+ List_iterator<Drop_table_rcontext> drop_rctx_it(tables);
+ Drop_table_rcontext *drop_rctx;
Foreign_key_name *fk_name;
*parents_to_lock= NULL;
fk_names_to_lock->empty();
*has_not_locked_parent_or_fk_name= FALSE;
- for (table= tables; table; table= table->next_local)
+ while ((drop_rctx= drop_rctx_it++))
{
/* Skip this table if it is a temporary table. */
- if (table->table)
+ if (drop_rctx->is_temporary)
continue;
/*
@@ -2308,10 +2349,10 @@ fk_check_tables_before_drop(THD *thd, TA
away long ago b) even if they exist they should be dropped when
normal table with which they are associated is dropped.
*/
- if (table->internal_tmp_table)
+ if (drop_rctx->table->internal_tmp_table)
continue;
- key_length= create_table_def_key(thd, key, table, 0);
+ key_length= create_table_def_key(thd, key, drop_rctx->table, 0);
/*
We ignore ER_NO_SUCH_TABLE error in order to avoid failing with this
@@ -2325,8 +2366,8 @@ fk_check_tables_before_drop(THD *thd, TA
*/
thd->push_internal_handler(&non_fatal_error_silencer);
pthread_mutex_lock(&LOCK_open);
- share= get_table_share_with_create(thd, table, key, key_length, OPEN_VIEW,
- &error);
+ share= get_table_share_with_create(thd, drop_rctx->table, key,
+ key_length, OPEN_VIEW, &error);
pthread_mutex_unlock(&LOCK_open);
thd->pop_internal_handler();
@@ -2345,13 +2386,13 @@ fk_check_tables_before_drop(THD *thd, TA
*/
while ((fk_p_s= fkeys_p_it++))
{
- if (! find_table_in_local_list(tables, fk_p_s->child_table_db.str,
- fk_p_s->child_table_name.str))
+ if (! find_table_in_list(tables, fk_p_s->child_table_db.str,
+ fk_p_s->child_table_name.str))
{
my_error(ER_FK_CHILD_TABLE_EXISTS, MYF(0), fk_p_s->name.str,
thd->lex->sql_command == SQLCOM_DROP_DB ? "DROP DATABASE" :
"DROP TABLE",
- table->table_name);
+ drop_rctx->table->table_name);
pthread_mutex_lock(&LOCK_open);
release_table_share(share);
pthread_mutex_unlock(&LOCK_open);
@@ -2404,7 +2445,7 @@ fk_check_tables_before_drop(THD *thd, TA
fk_c_s->parent_table_db.str,
fk_c_s->parent_table_name.str) ||
! thd->mdl_context.is_exclusive_lock_owner(TYPE_ENUM_FOREIGN_KEY,
- table->db, fk_c_s->name.str)))
+ drop_rctx->table->db, fk_c_s->name.str)))
*has_not_locked_parent_or_fk_name= TRUE;
if (fk_drop_table_add_parent_table(thd, parents_to_lock,
@@ -2417,15 +2458,15 @@ fk_check_tables_before_drop(THD *thd, TA
return TRUE;
}
- LEX_STRING child_table_db= { table->db, table->db_length };
+ LEX_STRING child_table_db= { drop_rctx->table->db,
+ drop_rctx->table->db_length };
- if (! fk_find_name_in_list(*fk_names_to_lock, table->db,
+ if (! fk_find_name_in_list(*fk_names_to_lock, drop_rctx->table->db,
fk_c_s->name.str) &&
(! (fk_name= Foreign_key_name::create(thd->mem_root,
child_table_db,
fk_c_s->name)) ||
fk_names_to_lock->push_back(fk_name, thd->mem_root)))
-
{
pthread_mutex_lock(&LOCK_open);
release_table_share(share);
@@ -2465,20 +2506,22 @@ fk_check_tables_before_drop(THD *thd, TA
static bool
fk_check_tables_before_drop(THD *thd,
- TABLE_LIST *tables, TABLE_LIST **parents_locked,
+ List<Drop_table_rcontext> &tables,
+ TABLE_LIST **parents_locked,
List<Foreign_key_name> *fk_names_locked)
{
- TABLE_LIST *table;
+ List_iterator<Drop_table_rcontext> drop_rctx_it(tables);
+ Drop_table_rcontext *drop_rctx;
TABLE_SHARE *share;
Foreign_key_name *fk_name;
- for (table= tables; table; table= table->next_local)
+ while ((drop_rctx= drop_rctx_it++))
{
/* Skip this table if it is a temporary table. */
- if (table->table->s->tmp_table != NO_TMP_TABLE)
+ if (drop_rctx->is_temporary)
continue;
- share= table->table->s;
+ share= drop_rctx->table->table->s;
List_iterator<Foreign_key_parent_share> fkeys_p_it(share->
fkeys.fkeys_parent);
@@ -2486,13 +2529,13 @@ fk_check_tables_before_drop(THD *thd,
while ((fk_p_s= fkeys_p_it++))
{
- if (! find_table_in_local_list(tables, fk_p_s->child_table_db.str,
- fk_p_s->child_table_name.str))
+ if (! find_table_in_list(tables, fk_p_s->child_table_db.str,
+ fk_p_s->child_table_name.str))
{
my_error(ER_FK_CHILD_TABLE_EXISTS, MYF(0), fk_p_s->name.str,
thd->lex->sql_command == SQLCOM_DROP_DB ? "DROP DATABASE" :
"DROP TABLE",
- table->table_name);
+ drop_rctx->table->table_name);
return TRUE;
}
}
@@ -2502,9 +2545,8 @@ fk_check_tables_before_drop(THD *thd,
while ((fk_c_s= fkeys_c_it++))
{
- if (! find_table_in_local_list(tables,
- fk_c_s->parent_table_db.str,
- fk_c_s->parent_table_name.str) &&
+ if (! find_table_in_list(tables, fk_c_s->parent_table_db.str,
+ fk_c_s->parent_table_name.str) &&
! find_table_in_local_list(*parents_locked,
fk_c_s->parent_table_db.str,
fk_c_s->parent_table_name.str))
@@ -2531,7 +2573,8 @@ fk_check_tables_before_drop(THD *thd,
@sa fk_take_mdl_on_fk_names().
*/
- fk_name= thd->locked_tables_list.find_fk_name(table->db, fk_c_s->name.str);
+ fk_name= thd->locked_tables_list.find_fk_name(drop_rctx->table->db,
+ fk_c_s->name.str);
DBUG_ASSERT(fk_name);
if (fk_names_locked->push_back(fk_name, thd->mem_root))
@@ -2589,6 +2632,9 @@ int mysql_rm_table_part2(THD *thd, TABLE
List<Foreign_key_name> fk_names_to_lock, fk_names_locked;
List_iterator<Foreign_key_name> fk_names_it(fk_names_locked);
Foreign_key_name *fk_name;
+ List<Drop_table_rcontext> dropped_tables;
+ List_iterator<Drop_table_rcontext> drop_rctx_it(dropped_tables);
+ Drop_table_rcontext *drop_rctx;
DBUG_ENTER("mysql_rm_table_part2");
LINT_INIT(alias);
@@ -2613,18 +2659,28 @@ int mysql_rm_table_part2(THD *thd, TABLE
if (!drop_temporary)
global_schema_lock_guard.lock();
+ /* Create per-table runtime contexts for the operation. */
+ for (table= tables; table; table= table->next_local)
+ {
+ if (! (drop_rctx= new(thd->mem_root) Drop_table_rcontext(table)) ||
+ dropped_tables.push_back(drop_rctx, thd->mem_root))
+ DBUG_RETURN(1);
+ }
+
/*
If we have the table in the definition cache, we don't have to check the
.frm file to find if the table is a normal table (not view) and what
engine to use.
*/
pthread_mutex_lock(&LOCK_open);
- for (table= tables; table; table= table->next_local)
+ while ((drop_rctx= drop_rctx_it++))
{
TABLE_SHARE *share;
- table->db_type= NULL;
+
+ table= drop_rctx->table;
+
if ((share= get_cached_table_share(table->db, table->table_name)))
- table->db_type= share->db_type();
+ drop_rctx->table_type= share->db_type();
/* Disable drop of enabled log tables */
if (share && (share->table_category == TABLE_CATEGORY_PERFORMANCE) &&
@@ -2646,23 +2702,18 @@ int mysql_rm_table_part2(THD *thd, TABLE
some expensive steps (like foreign key handling). Also our foreign
key code relies on this.
*/
- for (table= tables; table; table= table->next_local)
+ drop_rctx_it.rewind();
+ while ((drop_rctx= drop_rctx_it++))
{
- if ((table->table= find_temporary_table(thd, table->db,
- table->table_name)))
- {
- /*
- Since we don't acquire metadata lock if we have found temporary
- table, we should do something to avoid releasing it at the end.
- */
- table->mdl_request= 0;
- }
+ if (find_temporary_table(thd, drop_rctx->table->db,
+ drop_rctx->table->table_name))
+ drop_rctx->is_temporary= TRUE;
}
if (!thd->locked_tables_mode)
{
retry_lock:
- if (lock_dropped_and_parent_tables(thd, tables,
+ if (lock_dropped_and_parent_tables(thd, dropped_tables,
parents_to_lock, fk_names_to_lock))
DBUG_RETURN(1);
parents_locked= parents_to_lock;
@@ -2670,7 +2721,7 @@ retry_lock:
if (opt_fk_all_engines)
{
- if (fk_check_tables_before_drop(thd, tables,
+ if (fk_check_tables_before_drop(thd, dropped_tables,
&parents_to_lock, &fk_names_to_lock,
&has_not_locked_parent_or_fk_name))
DBUG_RETURN(1);
@@ -2685,20 +2736,24 @@ retry_lock:
}
else
{
- for (table= tables; table; table= table->next_local)
- if (! table->table)
+ drop_rctx_it.rewind();
+ while ((drop_rctx= drop_rctx_it++))
+ {
+ if (! drop_rctx->is_temporary)
{
/*
Check that each non-temporary table to be dropped is locked
for write and cache pointer to its TABLE object for lock
upgrade.
*/
+ table= drop_rctx->table;
table->table= find_write_locked_table(thd->open_tables, table->db,
table->table_name);
if (!table->table)
DBUG_RETURN(1);
table->mdl_request->ticket= table->table->mdl_ticket;
}
+ }
/*
Check that we are not dropping parent tables withour dropping child
@@ -2708,7 +2763,7 @@ retry_lock:
not among tables to be dropped to use for this upgrade.
*/
if (opt_fk_all_engines &&
- fk_check_tables_before_drop(thd, tables, &parents_locked,
+ fk_check_tables_before_drop(thd, dropped_tables, &parents_locked,
&fk_names_locked))
DBUG_RETURN(1);
@@ -2719,7 +2774,7 @@ retry_lock:
Also upgrade meta-data locks on foreign key names so we can safely
mark them as unused when dropping their child tables.
*/
- if (upgrade_mdl_for_dropped_and_parent_tables(thd, tables,
+ if (upgrade_mdl_for_dropped_and_parent_tables(thd, dropped_tables,
parents_locked,
fk_names_locked))
{
@@ -2729,13 +2784,16 @@ retry_lock:
}
}
- for (table= tables; table; table= table->next_local)
+ drop_rctx_it.rewind();
+ while ((drop_rctx= drop_rctx_it++))
{
- char *db=table->db;
+ char *db= drop_rctx->table->db;
handlerton *table_type;
enum legacy_db_type frm_db_type;
Foreign_key_ddl_rcontext fk_ctx(thd, TRUE);
+ table= drop_rctx->table;
+
DBUG_PRINT("table", ("table_l: '%s'.'%s' table: %p s: %p",
table->db, table->table_name, table->table,
table->table ? table->table->s : (TABLE_SHARE *)-1));
@@ -2745,8 +2803,8 @@ retry_lock:
switch (error) {
case 0:
// removed temporary table
+ DBUG_ASSERT(drop_temporary || drop_rctx->is_temporary);
tmp_table_deleted= 1;
- table->table= 0;
continue;
case -1:
DBUG_ASSERT(thd->in_sub_stmt);
@@ -2754,6 +2812,7 @@ retry_lock:
goto err;
default:
// temporary table not found
+ DBUG_ASSERT(! drop_rctx->is_temporary);
error= 0;
}
@@ -2783,11 +2842,11 @@ retry_lock:
built_query.append("`,");
}
- table_type= table->db_type;
+ table_type= drop_rctx->table_type;
if (!drop_temporary)
{
if (opt_fk_all_engines &&
- fk_ctx.prepare_drop_table(table, tables, parents_locked))
+ fk_ctx.prepare_drop_table(table, dropped_tables, parents_locked))
{
error= 1;
goto err_table;
@@ -3038,16 +3097,18 @@ err:
thd->locked_tables_list.unlock_locked_tables(thd);
goto end;
}
- for (table= tables; table; table= table->next_local)
+ drop_rctx_it.rewind();
+ while ((drop_rctx= drop_rctx_it++))
{
- if (table->mdl_request)
+ if (! drop_rctx->is_temporary)
{
/*
Under LOCK TABLES we may have several instances of table open
and locked and therefore have to remove several metadata lock
requests associated with them.
*/
- thd->mdl_context.release_all_locks_for_name(table->mdl_request->ticket);
+ thd->mdl_context.release_all_locks_for_name(drop_rctx->table->
+ mdl_request->ticket);
}
}
while ((fk_name= fk_names_it++))
=== modified file 'sql/table.h'
--- a/sql/table.h 2009-05-14 14:18:43 +0000
+++ b/sql/table.h 2009-05-18 11:37:41 +0000
@@ -1424,7 +1424,6 @@ struct TABLE_LIST
bool check_option_processed;
/* FRMTYPE_ERROR if any type is acceptable */
enum frm_type_enum required_type;
- handlerton *db_type; /* table_type for handler */
char timestamp_buffer[20]; /* buffer for timestamp (19+1) */
/*
This TABLE_LIST object is just placeholder for prelocking, it will be
Attachment: [text/bzr-bundle] bzr/dlenev@mysql.com-20090518113741-fpfjdjx1p01pvccf.bundle
| Thread |
|---|
| • bzr commit into mysql-6.1-fk branch (dlenev:2734) WL#148 | Dmitry Lenev | 18 May |