From: Dmitry Lenev Date: March 31 2011 6:39am Subject: bzr commit into mysql-trunk branch (Dmitry.Lenev:3534) Bug#11746602 List-Archive: http://lists.mysql.com/commits/134331 X-Bug: 11746602 Message-Id: <20110331063946.D90307405D5@bandersnatch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2028398190==" --===============2028398190== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/dlenev/src/bzr/mysql-trunk-bug27480-2/ based on revid:dmitry.lenev@stripped 3534 Dmitry Lenev 2011-03-31 Yet another follow-up for the patch for Bug#11746602 27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). This patch tries to eliminate performance overhead which was introduced by one of previous patches for this bug. One of those patches added pre-opening of temporary tables as a separate stage of statement execution, handled by a separate call to open_temporary_tables(). As result we started to construct table definition key twice per statement almost for each table to be open by statement. This patch addresses the issue by changing code to avoid construction of keys and borrowing pre-constructed key from TABLE_LIST::mdl_request::key instead, where it is possible. @ sql/sql_admin.cc Adjusted prepare_for_repair() code to use get_table_def_key() instead of create_table_def_key() to get table definition cache key (the former piggy-backs on pre-constructed TABLE_LIST::mdl_request::key instead of constructing new instance of key like the latter). @ sql/sql_base.cc - Introduced get_table_def_key() function which allows to get table definition cache key for the table list element cheaply, by piggy-backing on pre-constructed TABLE_LIST::mdl_request::key. Adjusted code to use this function instead of create_table_def_key(), which constructs new instance of key, where possible. - Made create_table_def_key() private to sql_base.cc as it is no longer used outside of this file. Also changed it to accept database and table name instead of table list element since now it is only used in cases when table list element is not easily available. Changed some code which specifically constructed temporary TABLE_LIST objects to call create_table_def_key() to not to do this. - Changed find_temporary_table(TABLE_LIST) to use key borrowed from TABLE_LIST::mdl_request::key instead of especially constructed key. This change allows us to save on key construction but adds a small overhead during key comparison. Such a trade-off should be acceptable as overhead during key comparison is only a few instructions. - Signatures of get_table_share/get_table_share_with_discover() and tdc_open_view() were changed to accept constant table definition key to allow them to be used in cases when keys were borrowed from MDL subsystem. @ sql/sql_base.h - Introduced get_table_def_key() function which allows to get table definition cache key for the table list element cheaply, by piggy-backing on pre-constructed TABLE_LIST::mdl_request::key. key, where possible. - Made create_table_def_key() private to sql_base.cc as it is no longer used outside of this file. - Signatures of get_table_share/get_table_share_with_discover() and tdc_open_view() were changed to accept constant table definition key to allow them to be used in cases when keys were borrowed from MDL subsystem. @ sql/sql_show.cc Adjusted fill_schema_table_from_frm() code to use get_table_def_key() instead of create_table_def_key() to get table definition cache key (the former piggy-backs on pre-constructed TABLE_LIST::mdl_request::key instead of constructing new instance of key like the latter). @ sql/sql_table.cc Changed two places in mysql_alter_table() code where we tried to open tables using table list element objects which were not fully/correctly initialized and which, therefore, were impossible to use to get table definition cache key from them. @ sql/sql_view.cc Adjusted fill_defined_view_parts() code to use get_table_def_key() instead of create_table_def_key() to get table definition cache key (the former piggy-backs on pre-constructed TABLE_LIST::mdl_request::key instead of constructing new instance of key like the latter). @ sql/table.cc Changed signature of alloc_table_share() to accept constant table definition key to allow it to be used in cases when key is borrowed from MDL subsystem. @ sql/table.h Changed signature of alloc_table_share() to accept constant table definition key to allow it to be used in cases when key is borrowed from MDL subsystem. modified: sql/sql_admin.cc sql/sql_base.cc sql/sql_base.h sql/sql_show.cc sql/sql_table.cc sql/sql_view.cc sql/table.cc sql/table.h === modified file 'sql/sql_admin.cc' --- a/sql/sql_admin.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_admin.cc 2011-03-31 06:39:38 +0000 @@ -65,7 +65,7 @@ static int prepare_for_repair(THD *thd, if (!(table= table_list->table)) { - char key[MAX_DBKEY_LENGTH]; + const char *key; uint key_length; /* If the table didn't exist, we have a shared metadata lock @@ -81,7 +81,6 @@ static int prepare_for_repair(THD *thd, */ my_hash_value_type hash_value; - key_length= create_table_def_key(thd, key, table_list, 0); table_list->mdl_request.init(MDL_key::TABLE, table_list->db, table_list->table_name, MDL_EXCLUSIVE, MDL_TRANSACTION); @@ -91,6 +90,8 @@ static int prepare_for_repair(THD *thd, DBUG_RETURN(0); has_mdl_lock= TRUE; + key_length= get_table_def_key(table_list, &key); + hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length); mysql_mutex_lock(&LOCK_open); share= get_table_share(thd, table_list, key, key_length, 0, === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2011-03-26 10:56:27 +0000 +++ b/sql/sql_base.cc 2011-03-31 06:39:38 +0000 @@ -222,17 +222,16 @@ static void check_unused(void) #endif -/* +/** Create a table cache key - SYNOPSIS - create_table_def_key() - thd Thread handler - key Create key here (must be of size MAX_DBKEY_LENGTH) - table_list Table definition - tmp_table Set if table is a tmp table + @param thd Thread context + @param key Create key here (must be of size MAX_DBKEY_LENGTH) + @param db Database name. + @param table_name Table name. + @param tmp_table Set if table is a tmp table. - IMPLEMENTATION + @note The table cache_key is created from: db_name + \0 table_name + \0 @@ -243,16 +242,14 @@ static void check_unused(void) 4 bytes for master thread id 4 bytes pseudo thread id - RETURN - Length of key + @return Length of key. */ -uint create_table_def_key(THD *thd, char *key, - const TABLE_LIST *table_list, - bool tmp_table) +static uint create_table_def_key(THD *thd, char *key, + const char *db, const char *table_name, + bool tmp_table) { - uint key_length= (uint) (strmov(strmov(key, table_list->db)+1, - table_list->table_name)-key)+1; + uint key_length= (uint) (strmov(strmov(key, db)+1, table_name)-key)+1; if (tmp_table) { int4store(key + key_length, thd->server_id); @@ -263,6 +260,41 @@ uint create_table_def_key(THD *thd, char } +/** + Get table cache key for a table list element. + + @param table_list[in] Table list element. + @param key[out] On return points to table cache key for the table. + + @note Unlike create_table_def_key() call this function doesn't construct + key in a buffer provider by caller. Instead it relies on the fact + that table list element for which key is requested has properly + initialized MDL_request object and the fact that table defition + cache key is suffix of key used in MDL subsystem. So to get table + definition key it simply needs to return pointer to appropriate + part of MDL_key object nested in this table list element. + Indeed, this means that lifetime of key produced by this call is + limited by the lifetime of table list element which it got as + parameter. + + @return Length of key. +*/ + +uint get_table_def_key(const TABLE_LIST *table_list, const char **key) +{ + /* + This call relies on the fact that TABLE_LIST::mdl_request::key object + is properly initialized, so table definition cache can be produced + from key used by MDL subsystem. + */ + DBUG_ASSERT(!strcmp(table_list->db, table_list->mdl_request.key.db_name()) && + !strcmp(table_list->table_name, table_list->mdl_request.key.name())); + + *key= (const char*)table_list->mdl_request.key.ptr() + 1; + return table_list->mdl_request.key.length() - 1; +} + + /***************************************************************************** Functions to handle table definition cach (TABLE_SHARE) @@ -494,8 +526,9 @@ static void table_def_unuse_table(TABLE # Share for table */ -TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, - uint key_length, uint db_flags, int *error, +TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, + const char *key, uint key_length, + uint db_flags, int *error, my_hash_value_type hash_value) { TABLE_SHARE *share; @@ -610,7 +643,7 @@ found: static TABLE_SHARE * get_table_share_with_discover(THD *thd, TABLE_LIST *table_list, - char *key, uint key_length, + const char *key, uint key_length, uint db_flags, int *error, my_hash_value_type hash_value) @@ -755,14 +788,11 @@ void release_table_share(TABLE_SHARE *sh TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) { - char key[NAME_LEN*2+2]; - TABLE_LIST table_list; + char key[MAX_DBKEY_LENGTH]; uint key_length; mysql_mutex_assert_owner(&LOCK_open); - table_list.db= (char*) db; - table_list.table_name= (char*) table_name; - key_length= create_table_def_key((THD*) 0, key, &table_list, 0); + key_length= create_table_def_key((THD*) 0, key, db, table_name, 0); return (TABLE_SHARE*) my_hash_search(&table_def_cache, (uchar*) key, key_length); } @@ -1990,12 +2020,9 @@ void update_non_unique_table_error(TABLE TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name) { - TABLE_LIST tl; - - tl.db= (char*) db; - tl.table_name= (char*) table_name; - - return find_temporary_table(thd, &tl); + char key[MAX_DBKEY_LENGTH]; + uint key_length= create_table_def_key(thd, key, db, table_name, 1); + return find_temporary_table(thd, key, key_length); } @@ -2008,10 +2035,25 @@ TABLE *find_temporary_table(THD *thd, co TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl) { - char key[MAX_DBKEY_LENGTH]; - uint key_length= create_table_def_key(thd, key, tl, 1); + const char *key; + uint key_length; + char key_suffix[TMP_TABLE_KEY_EXTRA]; + TABLE *table; - return find_temporary_table(thd, key, key_length); + key_length= get_table_def_key(tl, &key); + + int4store(key_suffix, thd->server_id); + int4store(key_suffix + 4, thd->variables.pseudo_thread_id); + + for (table= thd->temporary_tables; table; table= table->next) + { + if ((table->s->table_cache_key.length == key_length+TMP_TABLE_KEY_EXTRA) && + !memcmp(table->s->table_cache_key.str, key, key_length) && + !memcmp(table->s->table_cache_key.str + key_length, key_suffix, + TMP_TABLE_KEY_EXTRA)) + return table; + } + return NULL; } @@ -2186,15 +2228,12 @@ bool rename_temporary_table(THD* thd, TA char *key; uint key_length; TABLE_SHARE *share= table->s; - TABLE_LIST table_list; DBUG_ENTER("rename_temporary_table"); if (!(key=(char*) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH))) DBUG_RETURN(1); /* purecov: inspected */ - table_list.db= (char*) db; - table_list.table_name= (char*) table_name; - key_length= create_table_def_key(thd, key, &table_list, 1); + key_length= create_table_def_key(thd, key, db, table_name, 1); share->set_table_cache_key(key, key_length); DBUG_RETURN(0); } @@ -2600,8 +2639,8 @@ bool open_table(THD *thd, TABLE_LIST *ta Open_table_context *ot_ctx) { reg1 TABLE *table; - char key[MAX_DBKEY_LENGTH]; - uint key_length; + const char *key; + uint key_length; char *alias= table_list->alias; uint flags= ot_ctx->get_flags(); MDL_ticket *mdl_ticket; @@ -2625,7 +2664,7 @@ bool open_table(THD *thd, TABLE_LIST *ta if (thd->killed) DBUG_RETURN(TRUE); - key_length= create_table_def_key(thd, key, table_list, 0); + key_length= get_table_def_key(table_list, &key); /* If we're in pre-locked or LOCK TABLES mode, let's try to find the @@ -3664,7 +3703,7 @@ check_and_update_routine_version(THD *th */ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias, - char *cache_key, uint cache_key_length, + const char *cache_key, uint cache_key_length, MEM_ROOT *mem_root, uint flags) { TABLE not_used; @@ -3765,15 +3804,15 @@ static bool open_table_entry_fini(THD *t static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) { - char cache_key[MAX_DBKEY_LENGTH]; - uint cache_key_length; + const char *cache_key; + uint cache_key_length; TABLE_SHARE *share; TABLE *entry; int not_used; bool result= TRUE; my_hash_value_type hash_value; - cache_key_length= create_table_def_key(thd, cache_key, table_list, 0); + cache_key_length= get_table_def_key(table_list, &cache_key); thd->clear_error(); @@ -5883,7 +5922,6 @@ TABLE *open_table_uncached(THD *thd, con TABLE_SHARE *share; char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path; uint key_length; - TABLE_LIST table_list; DBUG_ENTER("open_table_uncached"); DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s' server_id: %u " @@ -5891,10 +5929,8 @@ TABLE *open_table_uncached(THD *thd, con db, table_name, path, (uint) thd->server_id, (ulong) thd->variables.pseudo_thread_id)); - table_list.db= (char*) db; - table_list.table_name= (char*) table_name; /* Create the cache_key for temporary tables */ - key_length= create_table_def_key(thd, cache_key, &table_list, 1); + key_length= create_table_def_key(thd, cache_key, db, table_name, 1); if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table) + sizeof(*share) + strlen(path)+1 + key_length, === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2011-03-26 10:56:27 +0000 +++ b/sql/sql_base.h 2011-03-31 06:39:38 +0000 @@ -78,11 +78,10 @@ void table_def_start_shutdown(void); void assign_new_table_id(TABLE_SHARE *share); uint cached_open_tables(void); uint cached_table_definitions(void); -uint create_table_def_key(THD *thd, char *key, - const TABLE_LIST *table_list, - bool tmp_table); -TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, - uint key_length, uint db_flags, int *error, +uint get_table_def_key(const TABLE_LIST *table_list, const char **key); +TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, + const char *key, uint key_length, + uint db_flags, int *error, my_hash_value_type hash_value); void release_table_share(TABLE_SHARE *share); TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name); @@ -294,7 +293,7 @@ void tdc_remove_table(THD *thd, enum_tdc const char *db, const char *table_name, bool has_lock); bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias, - char *cache_key, uint cache_key_length, + const char *cache_key, uint cache_key_length, MEM_ROOT *mem_root, uint flags); void tdc_flush_unused_tables(); TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_show.cc 2011-03-31 06:39:38 +0000 @@ -3272,7 +3272,7 @@ static int fill_schema_table_from_frm(TH uint res= 0; int not_used; my_hash_value_type hash_value; - char key[MAX_DBKEY_LENGTH]; + const char *key; uint key_length; char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1]; @@ -3345,7 +3345,7 @@ static int fill_schema_table_from_frm(TH goto end; } - key_length= create_table_def_key(thd, key, &table_list, 0); + key_length= get_table_def_key(&table_list, &key); hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length); mysql_mutex_lock(&LOCK_open); share= get_table_share(thd, &table_list, key, === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2011-03-26 10:56:27 +0000 +++ b/sql/sql_table.cc 2011-03-31 06:39:38 +0000 @@ -6592,9 +6592,9 @@ bool mysql_alter_table(THD *thd,char *ne if (table->s->tmp_table) { TABLE_LIST tbl; - bzero((void*) &tbl, sizeof(tbl)); - tbl.db= new_db; - tbl.table_name= tbl.alias= tmp_name; + tbl.init_one_table(new_db, strlen(new_db), + tmp_name, strlen(tmp_name), + tmp_name, TL_READ_NO_INSERT); /* Table is in thd->temporary_tables */ (void) open_temporary_table(thd, &tbl); new_table= tbl.table; @@ -6890,15 +6890,15 @@ bool mysql_alter_table(THD *thd,char *ne NO need to tamper with MERGE tables. The real open is done later. */ Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); - TABLE *t_table; + TABLE_LIST temp_table_list; + TABLE_LIST *t_table_list; if (new_name != table_name || new_db != db) { - table_list->alias= new_name; - table_list->table_name= new_name; - table_list->table_name_length= strlen(new_name); - table_list->db= new_db; - table_list->db_length= strlen(new_db); - table_list->mdl_request.ticket= target_mdl_request.ticket; + temp_table_list.init_one_table(new_db, strlen(new_db), + new_name, strlen(new_name), + new_name, TL_READ_NO_INSERT); + temp_table_list.mdl_request.ticket= target_mdl_request.ticket; + t_table_list= &temp_table_list; } else { @@ -6908,20 +6908,21 @@ bool mysql_alter_table(THD *thd,char *ne to request the lock. */ table_list->mdl_request.ticket= mdl_ticket; + t_table_list= table_list; } - if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) + if (open_table(thd, t_table_list, thd->mem_root, &ot_ctx)) { goto err_with_mdl; } - t_table= table_list->table; /* 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); + error= t_table_list->table->file->ha_create_handler_files(path, NULL, + CHF_INDEX_FLAG, + create_info); - DBUG_ASSERT(thd->open_tables == t_table); + DBUG_ASSERT(thd->open_tables == t_table_list->table); close_thread_table(thd, &thd->open_tables); - table_list->table= 0; + t_table_list->table= 0; if (error) goto err_with_mdl; === modified file 'sql/sql_view.cc' --- a/sql/sql_view.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_view.cc 2011-03-31 06:39:38 +0000 @@ -209,13 +209,14 @@ static void make_valid_column_names(List static bool fill_defined_view_parts (THD *thd, TABLE_LIST *view) { - char key[MAX_DBKEY_LENGTH]; + const char *key; uint key_length; LEX *lex= thd->lex; TABLE_LIST decoy; memcpy (&decoy, view, sizeof (TABLE_LIST)); - key_length= create_table_def_key(thd, key, view, 0); + + key_length= get_table_def_key(view, &key); if (tdc_open_view(thd, &decoy, decoy.alias, key, key_length, thd->mem_root, OPEN_VIEW_NO_PARSE)) === modified file 'sql/table.cc' --- a/sql/table.cc 2011-03-01 14:47:01 +0000 +++ b/sql/table.cc 2011-03-31 06:39:38 +0000 @@ -311,7 +311,7 @@ TABLE_CATEGORY get_table_category(const # Share */ -TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, +TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, const char *key, uint key_length) { MEM_ROOT mem_root; === modified file 'sql/table.h' --- a/sql/table.h 2011-02-02 22:02:29 +0000 +++ b/sql/table.h 2011-03-31 06:39:38 +0000 @@ -2150,7 +2150,7 @@ void init_mdl_requests(TABLE_LIST *table int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, bool is_create_table); -TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, +TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, const char *key, uint key_length); void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, uint key_length, --===============2028398190== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.lenev@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.lenev@stripped # target_branch: file:///home/dlenev/src/bzr/mysql-trunk-bug27480-2/ # testament_sha1: 92fd056a6c676372cf0e16bae2ef0b8926943a3f # timestamp: 2011-03-31 10:39:46 +0400 # base_revision_id: dmitry.lenev@stripped\ # 99z45gv5gbex9yc5 # # Begin bundle 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 1I1MO9vDc429ud/Aj8hdyRThQkDo1Bjw --===============2028398190==--