From: Dmitry Lenev Date: May 21 2012 10:52am Subject: bzr push into mysql-trunk branch (Dmitry.Lenev:3901 to 3902) WL#5772 List-Archive: http://lists.mysql.com/commits/143866 Message-Id: <20120521105210.73C6A420339@jubjub> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3902 Dmitry Lenev 2012-05-21 WL#5772 "Add partitioned Table Definition Cache to avoid using LOCK_open and its derivatives in DML queries". Review change #13: - Use separate class for incapsulate operation on all table caches in the system instead of static methods in Table_cache class. modified: sql/mysqld.cc sql/sql_base.cc sql/sql_base.h sql/sql_parse.cc sql/sql_test.cc sql/sys_vars.cc sql/table.cc 3901 Dmitry Lenev 2012-05-17 WL#5772 "Add partitioned Table Definition Cache to avoid using LOCK_open and its derivatives in DML queries". Review change #12: - Changed Table_cache::free_table_all() not to use hash look up. modified: sql/sql_base.cc sql/sql_base.h === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2012-05-16 14:45:15 +0000 +++ b/sql/mysqld.cc 2012-05-21 10:48:21 +0000 @@ -6948,7 +6948,7 @@ static int show_open_tables(THD *thd, SH { var->type= SHOW_LONG; var->value= buff; - *((long *)buff)= (long)Table_cache::cached_tables(); + *((long *)buff)= (long)table_cache_manager.cached_tables(); return 0; } === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2012-05-17 11:14:28 +0000 +++ b/sql/sql_base.cc 2012-05-21 10:48:21 +0000 @@ -231,15 +231,10 @@ static void modify_slave_open_temp_table } -Table_cache Table_cache::m_table_cache[MAX_TABLE_CACHES]; - - -/** Get instance of table cache to be used by particular connection. */ - -Table_cache* Table_cache::get_cache(THD *thd) -{ - return &m_table_cache[thd->thread_id % table_cache_instances]; -} +/** + Container for all table cache instances in the system. +*/ +Table_cache_manager table_cache_manager; /** @@ -327,7 +322,7 @@ void Table_cache::destroy() @retval true - failure. */ -bool Table_cache::init_all() +bool Table_cache_manager::init() { for (uint i= 0; i < table_cache_instances; i++) { @@ -345,7 +340,7 @@ bool Table_cache::init_all() /** Destroy all instances of table cache which were used by server. */ -void Table_cache::destroy_all() +void Table_cache_manager::destroy() { for (uint i= 0; i < table_cache_instances; i++) m_table_cache[i].destroy(); @@ -359,12 +354,12 @@ void Table_cache::destroy_all() of tables is acceptable. */ -uint Table_cache::cached_tables() +uint Table_cache_manager::cached_tables() { uint result= 0; for (uint i= 0; i < table_cache_instances; i++) - result+= m_table_cache[i].m_table_count; + result+= m_table_cache[i].cached_tables(); return result; } @@ -375,10 +370,10 @@ uint Table_cache::cached_tables() cache (i.e. LOCK_open). */ -void Table_cache::lock_all_and_tdc() +void Table_cache_manager::lock_all_and_tdc() { for (uint i= 0; i < table_cache_instances; i++) - mysql_mutex_lock(&m_table_cache[i].m_lock); + m_table_cache[i].lock(); mysql_mutex_lock(&LOCK_open); } @@ -389,12 +384,12 @@ void Table_cache::lock_all_and_tdc() cache. */ -void Table_cache::unlock_all_and_tdc() +void Table_cache_manager::unlock_all_and_tdc() { mysql_mutex_unlock(&LOCK_open); for (uint i= 0; i < table_cache_instances; i++) - mysql_mutex_unlock(&m_table_cache[i].m_lock); + m_table_cache[i].unlock(); } @@ -402,10 +397,10 @@ void Table_cache::unlock_all_and_tdc() Assert that caller owns locks on all instances of table cache. */ -void Table_cache::assert_owner_all() +void Table_cache_manager::assert_owner_all() { for (uint i= 0; i < table_cache_instances; i++) - mysql_mutex_assert_owner(&m_table_cache[i].m_lock); + m_table_cache[i].assert_owner(); } @@ -414,7 +409,7 @@ void Table_cache::assert_owner_all() and table definition cache. */ -void Table_cache::assert_owner_all_and_tdc() +void Table_cache_manager::assert_owner_all_and_tdc() { assert_owner_all(); @@ -422,22 +417,6 @@ void Table_cache::assert_owner_all_and_t } -/** Acquire lock on table cache instance. */ - -void Table_cache::lock() -{ - mysql_mutex_lock(&m_lock); -} - - -/** Release lock on table cache instance. */ - -void Table_cache::unlock() -{ - mysql_mutex_unlock(&m_lock); -} - - /** Construct iterator over all used TABLE objects for the table share. @@ -447,7 +426,7 @@ void Table_cache::unlock() Table_cache_iterator::Table_cache_iterator(const TABLE_SHARE *share_arg) : share(share_arg), current_cache_index(0), current_table(NULL) { - Table_cache::assert_owner_all(); + table_cache_manager.assert_owner_all(); move_to_next_table(); } @@ -478,7 +457,7 @@ void Table_cache_iterator::move_to_next_ TABLE* Table_cache_iterator::operator ++(int) { - Table_cache::assert_owner_all(); + table_cache_manager.assert_owner_all(); TABLE *result= current_table; @@ -621,7 +600,7 @@ void Table_cache::check_unused() Print debug information for the contents of all table cache instances. */ -void Table_cache::print_tables_all() +void Table_cache_manager::print_tables() { puts("DB Table Version Thread Open Lock"); @@ -802,7 +781,7 @@ bool table_def_init(void) oldest_unused_share= &end_of_unused_share; end_of_unused_share.prev= &oldest_unused_share; - if (Table_cache::init_all()) + if (table_cache_manager.init()) { mysql_mutex_destroy(&LOCK_open); return true; @@ -830,7 +809,7 @@ void table_def_start_shutdown(void) { if (table_def_inited) { - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); /* Ensure that TABLE and TABLE_SHARE objects which are created for tables that are open during process of plugins' shutdown are @@ -838,7 +817,7 @@ void table_def_start_shutdown(void) plugins minimal and allows shutdown to proceed smoothly. */ table_def_shutdown_in_progress= true; - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); /* Free all cached but unused TABLEs and TABLE_SHAREs. */ close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT); } @@ -853,7 +832,7 @@ void table_def_free(void) table_def_inited= false; /* Free table definitions. */ my_hash_free(&table_def_cache); - Table_cache::destroy_all(); + table_cache_manager.destroy(); mysql_mutex_destroy(&LOCK_open); } DBUG_VOID_RETURN; @@ -916,7 +895,7 @@ bool Table_cache::add_used_table(THD *th { Table_cache_element *el; - mysql_mutex_assert_owner(&m_lock); + assert_owner(); DBUG_ASSERT(table->in_use == thd); @@ -924,7 +903,7 @@ bool Table_cache::add_used_table(THD *th Try to get Table_cache_element representing this table in the cache from array in the TABLE_SHARE. */ - el= table->s->cache_element[cache_index()]; + el= table->s->cache_element[table_cache_manager.cache_index(this)]; if (!el) { @@ -949,7 +928,7 @@ bool Table_cache::add_used_table(THD *th return true; } - table->s->cache_element[cache_index()]= el; + table->s->cache_element[table_cache_manager.cache_index(this)]= el; } /* Add table to the used tables list */ @@ -972,9 +951,10 @@ bool Table_cache::add_used_table(THD *th void Table_cache::remove_table(TABLE *table) { - Table_cache_element *el= table->s->cache_element[cache_index()]; + Table_cache_element *el= + table->s->cache_element[table_cache_manager.cache_index(this)]; - mysql_mutex_assert_owner(&m_lock); + assert_owner(); if (table->in_use) { @@ -999,7 +979,7 @@ void Table_cache::remove_table(TABLE *ta Remove reference to deleted cache element from array in the TABLE_SHARE. */ - table->s->cache_element[cache_index()]= NULL; + table->s->cache_element[table_cache_manager.cache_index(this)]= NULL; } } @@ -1033,7 +1013,7 @@ TABLE* Table_cache::get_table(THD *thd, Table_cache_element *el; TABLE *table; - mysql_mutex_assert_owner(&m_lock); + assert_owner(); *share= NULL; @@ -1083,9 +1063,10 @@ TABLE* Table_cache::get_table(THD *thd, void Table_cache::release_table(THD *thd, TABLE *table) { - Table_cache_element *el= table->s->cache_element[cache_index()]; + Table_cache_element *el= + table->s->cache_element[table_cache_manager.cache_index(this)]; - mysql_mutex_assert_owner(&m_lock); + assert_owner(); DBUG_ASSERT(table->in_use); DBUG_ASSERT(table->file); @@ -1440,7 +1421,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *t start_list= &open_list; open_list=0; - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); for (uint idx=0 ; result == 0 && idx < table_def_cache.records; idx++) { @@ -1477,7 +1458,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *t start_list= &(*start_list)->next; *start_list=0; } - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); DBUG_RETURN(open_list); } @@ -1529,7 +1510,7 @@ void free_io_cache(TABLE *table) static void kill_delayed_threads_for_table(TABLE_SHARE *share) { - Table_cache::assert_owner_all(); + table_cache_manager.assert_owner_all(); Table_cache_iterator it(share); TABLE *tab; @@ -1559,20 +1540,28 @@ static void kill_delayed_threads_for_tab void Table_cache::free_all_unused_tables() { - Table_cache::assert_owner_all_and_tdc(); + assert_owner(); - for (uint i= 0; i < table_cache_instances; i++) + while (m_unused_tables) { - while (m_table_cache[i].m_unused_tables) - { - TABLE *table_to_free= m_table_cache[i].m_unused_tables; - m_table_cache[i].remove_table(table_to_free); - intern_close_table(table_to_free); - } + TABLE *table_to_free= m_unused_tables; + remove_table(table_to_free); + intern_close_table(table_to_free); } } +/** Free all unused TABLE objects in all table cache instances. */ + +void Table_cache_manager::free_all_unused_tables() +{ + assert_owner_all_and_tdc(); + + for (uint i= 0; i < table_cache_instances; i++) + m_table_cache[i].free_all_unused_tables(); +} + + /* Close all tables which aren't in use by any thread @@ -1601,7 +1590,7 @@ bool close_cached_tables(THD *thd, TABLE DBUG_ENTER("close_cached_tables"); DBUG_ASSERT(thd || (!wait_for_refresh && !tables)); - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); if (!tables) { /* @@ -1621,7 +1610,7 @@ bool close_cached_tables(THD *thd, TABLE Get rid of all unused TABLE and TABLE_SHARE instances. By doing this we automatically close all tables which were marked as "old". */ - Table_cache::free_all_unused_tables(); + table_cache_manager.free_all_unused_tables(); /* Free table shares which were not freed implicitly by loop above. */ while (oldest_unused_share->next) (void) my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share); @@ -1646,7 +1635,7 @@ bool close_cached_tables(THD *thd, TABLE wait_for_refresh=0; // Nothing to wait for } - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); if (!wait_for_refresh) DBUG_RETURN(result); @@ -2184,7 +2173,7 @@ void close_thread_table(THD *thd, TABLE if (table->file != NULL) table->file->unbind_psi(); - Table_cache *tc= Table_cache::get_cache(thd); + Table_cache *tc= table_cache_manager.get_cache(thd); tc->lock(); @@ -3492,7 +3481,7 @@ bool open_table(THD *thd, TABLE_LIST *ta retry_share: { - Table_cache *tc= Table_cache::get_cache(thd); + Table_cache *tc= table_cache_manager.get_cache(thd); tc->lock(); @@ -3744,7 +3733,7 @@ share_found: } { /* Add new TABLE object to table cache for this connection. */ - Table_cache *tc= Table_cache::get_cache(thd); + Table_cache *tc= table_cache_manager.get_cache(thd); tc->lock(); @@ -4591,13 +4580,13 @@ static bool auto_repair_table(THD *thd, } my_free(entry); - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); release_table_share(share); /* Remove the repaired share from the table cache. */ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_list->db, table_list->table_name, TRUE); - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); return result; end_unlock: mysql_mutex_unlock(&LOCK_open); @@ -9797,9 +9786,9 @@ my_bool mysql_rm_tmp_tables(void) void tdc_flush_unused_tables() { - Table_cache::lock_all_and_tdc(); - Table_cache::free_all_unused_tables(); - Table_cache::unlock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); + table_cache_manager.free_all_unused_tables(); + table_cache_manager.unlock_all_and_tdc(); } @@ -9814,13 +9803,13 @@ void tdc_flush_unused_tables() @note Caller should own LOCK_open and locks on all table cache instances. */ -void Table_cache::free_table_all(THD *thd, - enum_tdc_remove_table_type remove_type, - TABLE_SHARE *share) +void Table_cache_manager::free_table(THD *thd, + enum_tdc_remove_table_type remove_type, + TABLE_SHARE *share) { Table_cache_element *cache_el[MAX_TABLE_CACHES]; - Table_cache::assert_owner_all_and_tdc(); + assert_owner_all_and_tdc(); /* Freeing last TABLE instance for the share will destroy the share @@ -9902,9 +9891,9 @@ void tdc_remove_table(THD *thd, enum_tdc TABLE_SHARE *share; if (! has_lock) - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); else - Table_cache::assert_owner_all_and_tdc(); + table_cache_manager.assert_owner_all_and_tdc(); DBUG_ASSERT(remove_type == TDC_RT_REMOVE_UNUSED || thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name, @@ -9929,14 +9918,14 @@ void tdc_remove_table(THD *thd, enum_tdc used. */ share->version= 0; - Table_cache::free_table_all(thd, remove_type, share); + table_cache_manager.free_table(thd, remove_type, share); } else (void) my_hash_delete(&table_def_cache, (uchar*) share); } if (! has_lock) - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); } === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2012-05-17 11:14:28 +0000 +++ b/sql/sql_base.h 2012-05-21 10:48:21 +0000 @@ -627,11 +627,6 @@ private: class Table_cache { -public: - - /** Maximum supported number of table cache instances. */ - static const int MAX_TABLE_CACHES= 64; - private: /** The table cache lock protects the following data: @@ -683,17 +678,8 @@ private: */ uint m_table_count; - /** - An array of Table_cache instances. - Only the first table_cache_instances elements in it are used. - */ - static Table_cache m_table_cache[MAX_TABLE_CACHES]; - private: - bool init(); - void destroy(); - #ifdef EXTRA_DEBUG void check_unused(); #else @@ -704,28 +690,17 @@ private: inline void free_unused_tables_if_necessary(THD *thd); - uint cache_index() const { return (this - &m_table_cache[0]); } - -#ifndef DBUG_OFF - void print_tables(); -#endif - public: - static bool init_all(); - static void destroy_all(); - - static Table_cache *get_cache(THD *thd); - - static uint cached_tables(); - - static void lock_all_and_tdc(); - static void unlock_all_and_tdc(); - static void assert_owner_all(); - static void assert_owner_all_and_tdc(); + bool init(); + void destroy(); - inline void lock(); - inline void unlock(); + /** Acquire lock on table cache instance. */ + void lock() { mysql_mutex_lock(&m_lock); } + /** Release lock on table cache instance. */ + void unlock() { mysql_mutex_unlock(&m_lock); } + /** Assert that caller owns lock on the table cache. */ + void assert_owner() { mysql_mutex_assert_owner(&m_lock); } inline TABLE* get_table(THD *thd, my_hash_value_type hash_value, const char *key, uint key_length, @@ -736,17 +711,69 @@ public: inline bool add_used_table(THD *thd, TABLE *table); inline void remove_table(TABLE *table); - static void free_table_all(THD *thd, - enum_tdc_remove_table_type remove_type, - TABLE_SHARE *share); + /** Get number of TABLE instances in the cache. */ + uint cached_tables() const { return m_table_count; } - static void free_all_unused_tables(); + void free_all_unused_tables(); #ifndef DBUG_OFF - static void print_tables_all(); + void print_tables(); +#endif +}; + + +/** + Container class for all table cache instances in the system. +*/ + +class Table_cache_manager +{ +public: + + /** Maximum supported number of table cache instances. */ + static const int MAX_TABLE_CACHES= 64; + + bool init(); + void destroy(); + + /** Get instance of table cache to be used by particular connection. */ + Table_cache* get_cache(THD *thd) + { + return &m_table_cache[thd->thread_id % table_cache_instances]; + } + + /** Get index for the table cache in container. */ + uint cache_index(Table_cache *cache) const + { + return (cache - &m_table_cache[0]); + } + + uint cached_tables(); + + void lock_all_and_tdc(); + void unlock_all_and_tdc(); + void assert_owner_all(); + void assert_owner_all_and_tdc(); + + void free_table(THD *thd, + enum_tdc_remove_table_type remove_type, + TABLE_SHARE *share); + + void free_all_unused_tables(); + +#ifndef DBUG_OFF + void print_tables(); #endif friend class Table_cache_iterator; + +private: + + /** + An array of Table_cache instances. + Only the first table_cache_instances elements in it are used. + */ + Table_cache m_table_cache[MAX_TABLE_CACHES]; }; @@ -769,4 +796,7 @@ public: void rewind(); }; + +extern Table_cache_manager table_cache_manager; + #endif /* SQL_BASE_INCLUDED */ === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2012-05-16 14:45:15 +0000 +++ b/sql/sql_parse.cc 2012-05-21 10:48:21 +0000 @@ -1576,7 +1576,7 @@ bool dispatch_command(enum enum_server_c current_global_status_var.long_query_count, current_global_status_var.opened_tables, refresh_version, - Table_cache::cached_tables(), + table_cache_manager.cached_tables(), (uint) (queries_per_second1000 / 1000), (uint) (queries_per_second1000 % 1000)); #ifdef EMBEDDED_LIBRARY === modified file 'sql/sql_test.cc' --- a/sql/sql_test.cc 2012-05-16 14:45:15 +0000 +++ b/sql/sql_test.cc 2012-05-21 10:48:21 +0000 @@ -83,15 +83,15 @@ print_where(Item *cond,const char *info, static void print_cached_tables(void) { /* purecov: begin tested */ - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); - Table_cache::print_tables_all(); + table_cache_manager.print_tables(); printf("\nCurrent refresh version: %ld\n",refresh_version); if (my_hash_check(&table_def_cache)) printf("Error: Table definition hash table is corrupted\n"); fflush(stdout); - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); /* purecov: end */ return; } @@ -390,7 +390,8 @@ static void display_table_locks(void) void *saved_base; DYNAMIC_ARRAY saved_table_locks; - (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), Table_cache::cached_tables() + 20,50); + (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), + table_cache_manager.cached_tables() + 20,50); mysql_mutex_lock(&THR_LOCK_lock); for (list= thr_lock_thread_list; list; list= list_rest(list)) { @@ -512,7 +513,7 @@ Open tables: %10lu\n\ Open files: %10lu\n\ Open streams: %10lu\n", (ulong) tmp.opened_tables, - (ulong) Table_cache::cached_tables(), + (ulong) table_cache_manager.cached_tables(), (ulong) my_file_opened, (ulong) my_stream_opened); === modified file 'sql/sys_vars.cc' --- a/sql/sys_vars.cc 2012-05-16 14:45:15 +0000 +++ b/sql/sys_vars.cc 2012-05-21 10:48:21 +0000 @@ -2774,7 +2774,7 @@ static Sys_var_ulong Sys_table_cache_siz static Sys_var_ulong Sys_table_cache_instances( "table_open_cache_instances", "The number of table cache instances", READ_ONLY GLOBAL_VAR(table_cache_instances), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, Table_cache::MAX_TABLE_CACHES), DEFAULT(1), + VALID_RANGE(1, Table_cache_manager::MAX_TABLE_CACHES), DEFAULT(1), BLOCK_SIZE(1)); static Sys_var_ulong Sys_thread_cache_size( === modified file 'sql/table.cc' --- a/sql/table.cc 2012-05-16 14:45:15 +0000 +++ b/sql/table.cc 2012-05-21 10:48:21 +0000 @@ -3274,7 +3274,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_fo if (gvisitor->m_lock_open_count++ == 0) { locked= TRUE; - Table_cache::lock_all_and_tdc(); + table_cache_manager.lock_all_and_tdc(); } Table_cache_iterator tables_it(this); @@ -3320,7 +3320,7 @@ end: if (locked) { DBUG_ASSERT(gvisitor->m_lock_open_count == 0); - Table_cache::unlock_all_and_tdc(); + table_cache_manager.unlock_all_and_tdc(); } return result; No bundle (reason: useless for push emails).