From: Mattias Jonsson Date: May 25 2012 8:43pm Subject: bzr push into mysql-trunk branch (mattias.jonsson:3901 to 3902) Bug#13838761 WL#4305 List-Archive: http://lists.mysql.com/commits/143968 X-Bug: 13838761 Message-Id: <201205252043.q4PKhfaJ012653@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3902 Mattias Jonsson 2012-05-24 bug#13838761 Reverting InnoDB part of WL#4305, which caused the regression. rb 1089 approved by Jimmy No easy/small test case have yet been found, but I have verified that it does not crash after 30 min of sysqa test as it does without this patch. modified: storage/innobase/handler/ha_innodb.cc storage/innobase/handler/ha_innodb.h 3901 Mayank Prasad 2012-05-25 Bug #14117145 SPURIOUS TEST FAILURES, TEST PERFORMANCE_SCHEMA.CONNECTION Details: - There were continuous disconnect statements one after another, without synchronization. That was causing race conditions. Fix: - Wait for each disconnect to finish explicitly and then do further disconnect. modified: mysql-test/suite/perfschema/include/connection_load.inc === modified file 'storage/innobase/handler/ha_innodb.cc' --- a/storage/innobase/handler/ha_innodb.cc revid:mayank.prasad@stripped +++ b/storage/innobase/handler/ha_innodb.cc revid:mattias.jonsson@stripped @@ -96,6 +96,9 @@ this program; if not, write to the Free # ifndef MYSQL_PLUGIN_IMPORT # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ + +/** to protect innobase_open_files */ +static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ static ulong commit_threads = 0; static mysql_mutex_t commit_threads_m; @@ -231,6 +234,8 @@ it every INNOBASE_WAKE_INTERVAL'th step. #define INNOBASE_WAKE_INTERVAL 32 static ulong innobase_active_counter = 0; +static hash_table_t* innobase_open_tables; + /** Allowed values of innodb_change_buffering */ static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = { "none", /* IBUF_USE_NONE */ @@ -257,6 +262,7 @@ const struct _ft_vft_ext ft_vft_ext_resu #ifdef HAVE_PSI_INTERFACE /* Keys to register pthread mutexes/cond in the current file with performance schema */ +static mysql_pfs_key_t innobase_share_mutex_key; static mysql_pfs_key_t commit_threads_m_key; static mysql_pfs_key_t commit_cond_mutex_key; static mysql_pfs_key_t commit_cond_key; @@ -264,6 +270,7 @@ static mysql_pfs_key_t commit_cond_key; static PSI_mutex_info all_pthread_mutexes[] = { {&commit_threads_m_key, "commit_threads_m", 0}, {&commit_cond_mutex_key, "commit_cond_mutex", 0}, + {&innobase_share_mutex_key, "innobase_share_mutex", 0} }; static PSI_cond_info all_innodb_conds[] = { @@ -620,6 +627,23 @@ static SHOW_VAR innodb_status_variables[ {NullS, NullS, SHOW_LONG} }; +/************************************************************************//** +Handling the shared INNOBASE_SHARE structure that is needed to provide table +locking. Register the table name if it doesn't exist in the hash table. */ +static +INNOBASE_SHARE* +get_share( +/*======*/ + const char* table_name); /*!< in: table to lookup */ + +/************************************************************************//** +Free the shared object that was registered with get_share(). */ +static +void +free_share( +/*=======*/ + INNOBASE_SHARE* share); /*!< in/own: share to free */ + /*****************************************************************//** Frees a possible InnoDB trx object associated with the current THD. @return 0 or error number */ @@ -3088,6 +3112,10 @@ innobase_change_buffering_inited_ok: ibuf_max_size_update(innobase_change_buffer_max_size); + innobase_open_tables = hash_create(200); + mysql_mutex_init(innobase_share_mutex_key, + &innobase_share_mutex, + MY_MUTEX_INIT_FAST); mysql_mutex_init(commit_threads_m_key, &commit_threads_m, MY_MUTEX_INIT_FAST); mysql_mutex_init(commit_cond_mutex_key, @@ -3146,11 +3174,14 @@ innobase_end( srv_fast_shutdown = (ulint) innobase_fast_shutdown; innodb_inited = 0; + hash_table_free(innobase_open_tables); + innobase_open_tables = NULL; if (innobase_shutdown_for_mysql() != DB_SUCCESS) { err = 1; } srv_free_paths_and_sizes(); my_free(internal_innobase_data_file_path); + mysql_mutex_destroy(&innobase_share_mutex); mysql_mutex_destroy(&commit_threads_m); mysql_mutex_destroy(&commit_cond_m); mysql_cond_destroy(&commit_cond); @@ -4173,8 +4204,8 @@ innobase_match_index_columns( } /*******************************************************************//** -This function builds a translation table in Innobase_share -object for fast index location with mysql array number from its +This function builds a translation table in INNOBASE_SHARE +structure for fast index location with mysql array number from its table->key_info structure. This also provides the necessary translation between the key order in mysql key_info and Innodb ib_table->indexes if they are not fully matched with each other. @@ -4191,7 +4222,7 @@ innobase_build_index_translation( dictionary */ dict_table_t* ib_table,/*!< in: table in Innodb data dictionary */ - Innobase_share* share) /*!< in/out: share object + INNOBASE_SHARE* share) /*!< in/out: share structure where index translation table will be constructed in. */ { @@ -4311,7 +4342,7 @@ static dict_index_t* innobase_index_lookup( /*==================*/ - Innobase_share* share, /*!< in: share object for index + INNOBASE_SHARE* share, /*!< in: share structure for index translation table. */ uint keynr) /*!< in: index number for the requested index */ @@ -4466,7 +4497,7 @@ ha_innobase::open( user_thd = NULL; - if (!(share=get_share())) { + if (!(share=get_share(name))) { DBUG_RETURN(1); } @@ -4579,6 +4610,7 @@ retry: REFMAN "innodb-troubleshooting.html for how " "you can resolve the problem.", norm_name); + free_share(share); my_errno = ENOENT; DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); @@ -4623,6 +4655,7 @@ table_opened: } if (!thd_tablespace_op(thd) && no_tablespace) { + free_share(share); my_errno = ENOENT; dict_table_close(ib_table, FALSE, FALSE); @@ -4858,6 +4891,8 @@ ha_innobase::close() upd_buf_size = 0; } + free_share(share); + MONITOR_INC(MONITOR_TABLE_CLOSE); /* Tell InnoDB server that there might be work for @@ -10163,7 +10198,7 @@ static int innobase_get_mysql_key_number_for_index( /*====================================*/ - Innobase_share* share, /*!< in: share object for index + INNOBASE_SHARE* share, /*!< in: share structure for index translation table. */ const TABLE* table, /*!< in: table in MySQL data dictionary */ @@ -12143,31 +12178,94 @@ innobase_show_status( } /************************************************************************//** -Handling the shared Innobase_share object that is needed to provide table -locking. */ -Innobase_share* -ha_innobase::get_share(void) -/*========================*/ +Handling the shared INNOBASE_SHARE structure that is needed to provide table +locking. Register the table name if it doesn't exist in the hash table. */ +static +INNOBASE_SHARE* +get_share( +/*======*/ + const char* table_name) { - Innobase_share *tmp_share; + INNOBASE_SHARE* share; - lock_shared_ha_data(); - tmp_share= static_cast(get_ha_share_ptr()); + mysql_mutex_lock(&innobase_share_mutex); - if (!tmp_share) - { - tmp_share= new Innobase_share; - if (!tmp_share) - { - unlock_shared_ha_data(); - return(NULL); - } + ulint fold = ut_fold_string(table_name); + + HASH_SEARCH(table_name_hash, innobase_open_tables, fold, + INNOBASE_SHARE*, share, + ut_ad(share->use_count > 0), + !strcmp(share->table_name, table_name)); + + if (!share) { + + uint length = (uint) strlen(table_name); + + /* TODO: invoke HASH_MIGRATE if innobase_open_tables + grows too big */ + + share = (INNOBASE_SHARE*) my_malloc(sizeof(*share)+length+1, + MYF(MY_FAE | MY_ZEROFILL)); + + share->table_name = (char*) memcpy(share + 1, + table_name, length + 1); + + HASH_INSERT(INNOBASE_SHARE, table_name_hash, + innobase_open_tables, fold, share); - set_ha_share_ptr(static_cast(tmp_share)); + thr_lock_init(&share->lock); + + /* Index translation table initialization */ + share->idx_trans_tbl.index_mapping = NULL; + share->idx_trans_tbl.index_count = 0; + share->idx_trans_tbl.array_size = 0; + } + + share->use_count++; + mysql_mutex_unlock(&innobase_share_mutex); + + return(share); +} + +/************************************************************************//** +Free the shared object that was registered with get_share(). */ +static +void +free_share( +/*=======*/ + INNOBASE_SHARE* share) /*!< in/own: table share to free */ +{ + mysql_mutex_lock(&innobase_share_mutex); + +#ifdef UNIV_DEBUG + INNOBASE_SHARE* share2; + ulint fold = ut_fold_string(share->table_name); + + HASH_SEARCH(table_name_hash, innobase_open_tables, fold, + INNOBASE_SHARE*, share2, + ut_ad(share->use_count > 0), + !strcmp(share->table_name, share2->table_name)); + + ut_a(share2 == share); +#endif /* UNIV_DEBUG */ + + if (!--share->use_count) { + ulint fold = ut_fold_string(share->table_name); + + HASH_DELETE(INNOBASE_SHARE, table_name_hash, + innobase_open_tables, fold, share); + thr_lock_delete(&share->lock); + + /* Free any memory from index translation table */ + my_free(share->idx_trans_tbl.index_mapping); + + my_free(share); + + /* TODO: invoke HASH_MIGRATE if innobase_open_tables + shrinks too much */ } - unlock_shared_ha_data(); - ut_ad(tmp_share); - return(tmp_share); + + mysql_mutex_unlock(&innobase_share_mutex); } /*****************************************************************//** === modified file 'storage/innobase/handler/ha_innodb.h' --- a/storage/innobase/handler/ha_innodb.h revid:mayank.prasad@stripped +++ b/storage/innobase/handler/ha_innodb.h revid:mattias.jonsson@stripped @@ -38,29 +38,19 @@ typedef struct innodb_idx_translate_stru /** InnoDB table share */ -class Innobase_share : public Handler_share -{ -public: +typedef struct st_innobase_share { THR_LOCK lock; /*!< MySQL lock protecting this structure */ + const char* table_name; /*!< InnoDB table name */ + uint use_count; /*!< reference count, + incremented in get_share() + and decremented in + free_share() */ + void* table_name_hash;/*!< hash table chain node */ innodb_idx_translate_t idx_trans_tbl; /*!< index translation table between MySQL and Innodb */ - Innobase_share() - { - thr_lock_init(&lock); - idx_trans_tbl.index_mapping = NULL; - idx_trans_tbl.index_count = 0; - idx_trans_tbl.array_size = 0; - } - ~Innobase_share() - { - thr_lock_delete(&lock); - - /* Free any memory from index translation table */ - my_free(idx_trans_tbl.index_mapping); - } -}; +} INNOBASE_SHARE; /** InnoDB B-tree index */ @@ -83,7 +73,7 @@ class ha_innobase: public handler currently using the handle; this is set in external_lock function */ THR_LOCK_DATA lock; - Innobase_share* share; /*!< information for MySQL + INNOBASE_SHARE* share; /*!< information for MySQL table locking */ uchar* upd_buf; /*!< buffer used in updates */ @@ -361,8 +351,6 @@ public: private: /** The multi range read session object */ DsMrr_impl ds_mrr; - /** Connects/gets Innobase_share in TABLE_SHARE */ - Innobase_share* get_share(); /* @} */ }; No bundle (reason: useless for push emails).