My Project
|
00001 /* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; version 2 of the License. 00006 00007 This program is distributed in the hope that it will be useful, 00008 but WITHOUT ANY WARRANTY; without even the implied warranty of 00009 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00010 GNU General Public License for more details. 00011 00012 You should have received a copy of the GNU General Public License 00013 along with this program; if not, write to the Free Software 00014 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 00015 00016 #ifndef TABLE_CACHE_INCLUDED 00017 #define TABLE_CACHE_INCLUDED 00018 00019 #include "my_global.h" 00020 #include "sql_class.h" 00021 #include "sql_base.h" 00022 00038 class Table_cache 00039 { 00040 private: 00064 mysql_mutex_t m_lock; 00065 00073 HASH m_cache; 00074 00081 TABLE *m_unused_tables; 00082 00089 uint m_table_count; 00090 00091 #ifdef HAVE_PSI_INTERFACE 00092 static PSI_mutex_key m_lock_key; 00093 static PSI_mutex_info m_mutex_keys[]; 00094 #endif 00095 00096 private: 00097 00098 #ifdef EXTRA_DEBUG 00099 void check_unused(); 00100 #else 00101 void check_unused() {} 00102 #endif 00103 inline void link_unused_table(TABLE *table); 00104 inline void unlink_unused_table(TABLE *table); 00105 00106 inline void free_unused_tables_if_necessary(THD *thd); 00107 00108 public: 00109 00110 bool init(); 00111 void destroy(); 00112 static void init_psi_keys(); 00113 00115 void lock() { mysql_mutex_lock(&m_lock); } 00117 void unlock() { mysql_mutex_unlock(&m_lock); } 00119 void assert_owner() { mysql_mutex_assert_owner(&m_lock); } 00120 00121 inline TABLE* get_table(THD *thd, my_hash_value_type hash_value, 00122 const char *key, uint key_length, 00123 TABLE_SHARE **share); 00124 00125 inline void release_table(THD *thd, TABLE *table); 00126 00127 inline bool add_used_table(THD *thd, TABLE *table); 00128 inline void remove_table(TABLE *table); 00129 00131 uint cached_tables() const { return m_table_count; } 00132 00133 void free_all_unused_tables(); 00134 00135 #ifndef DBUG_OFF 00136 void print_tables(); 00137 #endif 00138 }; 00139 00140 00145 class Table_cache_manager 00146 { 00147 public: 00148 00150 static const int MAX_TABLE_CACHES= 64; 00151 00152 bool init(); 00153 void destroy(); 00154 00156 Table_cache* get_cache(THD *thd) 00157 { 00158 return &m_table_cache[thd->thread_id % table_cache_instances]; 00159 } 00160 00162 uint cache_index(Table_cache *cache) const 00163 { 00164 return (cache - &m_table_cache[0]); 00165 } 00166 00167 uint cached_tables(); 00168 00169 void lock_all_and_tdc(); 00170 void unlock_all_and_tdc(); 00171 void assert_owner_all(); 00172 void assert_owner_all_and_tdc(); 00173 00174 void free_table(THD *thd, 00175 enum_tdc_remove_table_type remove_type, 00176 TABLE_SHARE *share); 00177 00178 void free_all_unused_tables(); 00179 00180 #ifndef DBUG_OFF 00181 void print_tables(); 00182 #endif 00183 00184 friend class Table_cache_iterator; 00185 00186 private: 00187 00192 Table_cache m_table_cache[MAX_TABLE_CACHES]; 00193 }; 00194 00195 00196 extern Table_cache_manager table_cache_manager; 00197 00198 00208 class Table_cache_element 00209 { 00210 private: 00211 /* 00212 Doubly-linked (back-linked) lists of used and unused TABLE objects 00213 for this table in this table cache (one such list per table cache). 00214 */ 00215 typedef I_P_List <TABLE, 00216 I_P_List_adapter<TABLE, 00217 &TABLE::cache_next, 00218 &TABLE::cache_prev> > TABLE_list; 00219 00220 TABLE_list used_tables; 00221 TABLE_list free_tables; 00222 TABLE_SHARE *share; 00223 00224 public: 00225 00226 Table_cache_element(TABLE_SHARE *share_arg) 00227 : share(share_arg) 00228 { 00229 } 00230 00231 TABLE_SHARE * get_share() const { return share; }; 00232 00233 friend class Table_cache; 00234 friend class Table_cache_manager; 00235 friend class Table_cache_iterator; 00236 }; 00237 00238 00244 class Table_cache_iterator 00245 { 00246 const TABLE_SHARE *share; 00247 uint current_cache_index; 00248 TABLE *current_table; 00249 00250 inline void move_to_next_table(); 00251 00252 public: 00258 inline Table_cache_iterator(const TABLE_SHARE *share_arg); 00259 inline TABLE* operator++(int); 00260 inline void rewind(); 00261 }; 00262 00263 00269 void Table_cache::link_unused_table(TABLE *table) 00270 { 00271 if (m_unused_tables) 00272 { 00273 table->next= m_unused_tables; 00274 table->prev= m_unused_tables->prev; 00275 m_unused_tables->prev= table; 00276 table->prev->next= table; 00277 } 00278 else 00279 m_unused_tables= table->next= table->prev= table; 00280 check_unused(); 00281 } 00282 00283 00286 void Table_cache::unlink_unused_table(TABLE *table) 00287 { 00288 table->next->prev= table->prev; 00289 table->prev->next= table->next; 00290 if (table == m_unused_tables) 00291 { 00292 m_unused_tables= m_unused_tables->next; 00293 if (table == m_unused_tables) 00294 m_unused_tables= NULL; 00295 } 00296 check_unused(); 00297 } 00298 00299 00309 void Table_cache::free_unused_tables_if_necessary(THD *thd) 00310 { 00311 /* 00312 We have too many TABLE instances around let us try to get rid of them. 00313 00314 Note that we might need to free more than one TABLE object, and thus 00315 need the below loop, in case when table_cache_size is changed dynamically, 00316 at server run time. 00317 */ 00318 if (m_table_count > table_cache_size_per_instance && m_unused_tables) 00319 { 00320 mysql_mutex_lock(&LOCK_open); 00321 while (m_table_count > table_cache_size_per_instance && 00322 m_unused_tables) 00323 { 00324 TABLE *table_to_free= m_unused_tables; 00325 remove_table(table_to_free); 00326 intern_close_table(table_to_free); 00327 thd->status_var.table_open_cache_overflows++; 00328 } 00329 mysql_mutex_unlock(&LOCK_open); 00330 } 00331 } 00332 00333 00346 bool Table_cache::add_used_table(THD *thd, TABLE *table) 00347 { 00348 Table_cache_element *el; 00349 00350 assert_owner(); 00351 00352 DBUG_ASSERT(table->in_use == thd); 00353 00354 /* 00355 Try to get Table_cache_element representing this table in the cache 00356 from array in the TABLE_SHARE. 00357 */ 00358 el= table->s->cache_element[table_cache_manager.cache_index(this)]; 00359 00360 if (!el) 00361 { 00362 /* 00363 If TABLE_SHARE doesn't have pointer to the element representing table 00364 in this cache, the element for the table must be absent from table the 00365 cache. 00366 00367 Allocate new Table_cache_element object and add it to the cache 00368 and array in TABLE_SHARE. 00369 */ 00370 DBUG_ASSERT(! my_hash_search(&m_cache, 00371 (uchar*)table->s->table_cache_key.str, 00372 table->s->table_cache_key.length)); 00373 00374 if (!(el= new Table_cache_element(table->s))) 00375 return true; 00376 00377 if (my_hash_insert(&m_cache, (uchar*)el)) 00378 { 00379 delete el; 00380 return true; 00381 } 00382 00383 table->s->cache_element[table_cache_manager.cache_index(this)]= el; 00384 } 00385 00386 /* Add table to the used tables list */ 00387 el->used_tables.push_front(table); 00388 00389 m_table_count++; 00390 00391 free_unused_tables_if_necessary(thd); 00392 00393 return false; 00394 } 00395 00396 00404 void Table_cache::remove_table(TABLE *table) 00405 { 00406 Table_cache_element *el= 00407 table->s->cache_element[table_cache_manager.cache_index(this)]; 00408 00409 assert_owner(); 00410 00411 if (table->in_use) 00412 { 00413 /* Remove from per-table chain of used TABLE objects. */ 00414 el->used_tables.remove(table); 00415 } 00416 else 00417 { 00418 /* Remove from per-table chain of unused TABLE objects. */ 00419 el->free_tables.remove(table); 00420 00421 /* And per-cache unused chain. */ 00422 unlink_unused_table(table); 00423 } 00424 00425 m_table_count--; 00426 00427 if (el->used_tables.is_empty() && el->free_tables.is_empty()) 00428 { 00429 (void) my_hash_delete(&m_cache, (uchar*) el); 00430 /* 00431 Remove reference to deleted cache element from array 00432 in the TABLE_SHARE. 00433 */ 00434 table->s->cache_element[table_cache_manager.cache_index(this)]= NULL; 00435 } 00436 } 00437 00438 00461 TABLE* Table_cache::get_table(THD *thd, my_hash_value_type hash_value, 00462 const char *key, uint key_length, 00463 TABLE_SHARE **share) 00464 { 00465 Table_cache_element *el; 00466 TABLE *table; 00467 00468 assert_owner(); 00469 00470 *share= NULL; 00471 00472 if (!(el= (Table_cache_element*) my_hash_search_using_hash_value(&m_cache, 00473 hash_value, (uchar*) key, key_length))) 00474 return NULL; 00475 00476 *share= el->share; 00477 00478 if ((table= el->free_tables.front())) 00479 { 00480 DBUG_ASSERT(!table->in_use); 00481 00482 /* 00483 Unlink table from list of unused TABLE objects for this 00484 table in this cache. 00485 */ 00486 el->free_tables.remove(table); 00487 00488 /* Unlink table from unused tables list for this cache. */ 00489 unlink_unused_table(table); 00490 00491 /* 00492 Add table to list of used TABLE objects for this table 00493 in the table cache. 00494 */ 00495 el->used_tables.push_front(table); 00496 00497 table->in_use= thd; 00498 /* The ex-unused table must be fully functional. */ 00499 DBUG_ASSERT(table->db_stat && table->file); 00500 /* The children must be detached from the table. */ 00501 DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); 00502 } 00503 00504 return table; 00505 } 00506 00507 00516 void Table_cache::release_table(THD *thd, TABLE *table) 00517 { 00518 Table_cache_element *el= 00519 table->s->cache_element[table_cache_manager.cache_index(this)]; 00520 00521 assert_owner(); 00522 00523 DBUG_ASSERT(table->in_use); 00524 DBUG_ASSERT(table->file); 00525 00526 /* We shouldn't put the table to 'unused' list if the share is old. */ 00527 DBUG_ASSERT(! table->s->has_old_version()); 00528 00529 table->in_use= NULL; 00530 00531 /* Remove TABLE from the list of used objects for the table in this cache. */ 00532 el->used_tables.remove(table); 00533 /* Add TABLE to the list of unused objects for the table in this cache. */ 00534 el->free_tables.push_front(table); 00535 /* Also link it last in the list of unused TABLE objects for the cache. */ 00536 link_unused_table(table); 00537 00538 /* 00539 We free the least used tables, not the subject table, to keep the LRU order. 00540 Note that in most common case the below call won't free anything. 00541 */ 00542 free_unused_tables_if_necessary(thd); 00543 } 00544 00545 00551 Table_cache_iterator::Table_cache_iterator(const TABLE_SHARE *share_arg) 00552 : share(share_arg), current_cache_index(0), current_table(NULL) 00553 { 00554 table_cache_manager.assert_owner_all(); 00555 move_to_next_table(); 00556 } 00557 00558 00561 void Table_cache_iterator::move_to_next_table() 00562 { 00563 for (; current_cache_index < table_cache_instances; ++current_cache_index) 00564 { 00565 Table_cache_element *el; 00566 00567 if ((el= share->cache_element[current_cache_index])) 00568 { 00569 if ((current_table= el->used_tables.front())) 00570 break; 00571 } 00572 } 00573 } 00574 00575 00582 TABLE* Table_cache_iterator::operator ++(int) 00583 { 00584 table_cache_manager.assert_owner_all(); 00585 00586 TABLE *result= current_table; 00587 00588 if (current_table) 00589 { 00590 Table_cache_element::TABLE_list::Iterator 00591 it(share->cache_element[current_cache_index]->used_tables, current_table); 00592 00593 current_table= ++it; 00594 00595 if (!current_table) 00596 { 00597 ++current_cache_index; 00598 move_to_next_table(); 00599 } 00600 } 00601 00602 return result; 00603 } 00604 00605 00606 void Table_cache_iterator::rewind() 00607 { 00608 current_cache_index= 0; 00609 current_table= NULL; 00610 move_to_next_table(); 00611 } 00612 00613 #endif /* TABLE_CACHE_INCLUDED */