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).
| Thread |
|---|
| • bzr push into mysql-trunk branch (Dmitry.Lenev:3901 to 3902) WL#5772 | Dmitry Lenev | 21 May |