Commit 98c4f167 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-4956 - Reduce usage of LOCK_open: TABLE_SHARE::tdc.used_tables

- tc_acquire_table and tc_release_table do not access
  TABLE_SHARE::tdc.used_tables anymore
- in tc_acquire_table(): release LOCK_tdc after we relase LOCK_open
  (saves a few CPU cycles in critical section)
- in tc_release_table(): if we reached table cache threshold, evict
  to-be-released table without moving it to unused_tables. unused_tables
  must be empty at this point.
parent b2c56742
......@@ -309,9 +309,11 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
share->table_name.str);
(*start_list)->in_use= 0;
mysql_mutex_lock(&LOCK_open);
TABLE_SHARE::TABLE_list::Iterator it(share->tdc.used_tables);
while (it++)
++(*start_list)->in_use;
TABLE_SHARE::All_share_tables_list::Iterator it(share->tdc.all_tables);
TABLE *table;
while ((table= it++))
if (table->in_use)
++(*start_list)->in_use;
mysql_mutex_unlock(&LOCK_open);
(*start_list)->locked= 0; /* Obsolete. */
start_list= &(*start_list)->next;
......@@ -371,16 +373,19 @@ void free_io_cache(TABLE *table)
void kill_delayed_threads_for_table(TABLE_SHARE *share)
{
TABLE_SHARE::TABLE_list::Iterator it(share->tdc.used_tables);
TABLE_SHARE::All_share_tables_list::Iterator it(share->tdc.all_tables);
TABLE *tab;
mysql_mutex_assert_owner(&LOCK_open);
if (!delayed_insert_threads)
return;
while ((tab= it++))
{
THD *in_use= tab->in_use;
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
if (in_use && (in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed)
{
in_use->killed= KILL_SYSTEM_THREAD;
......
......@@ -92,21 +92,23 @@ static void print_cached_tables(void)
mysql_mutex_lock(&LOCK_open);
while ((share= tdc_it.next()))
{
TABLE_SHARE::TABLE_list::Iterator it(share->tdc.used_tables);
TABLE_SHARE::All_share_tables_list::Iterator it(share->tdc.all_tables);
while ((entry= it++))
{
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
entry->s->db.str, entry->s->table_name.str, entry->s->version,
entry->in_use->thread_id, entry->db_stat ? 1 : 0,
lock_descriptions[(int)entry->reginfo.lock_type]);
}
it.init(share->tdc.free_tables);
while ((entry= it++))
{
unused++;
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
entry->s->db.str, entry->s->table_name.str, entry->s->version,
0L, entry->db_stat ? 1 : 0, "Not in use");
if (entry->in_use)
{
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
entry->s->db.str, entry->s->table_name.str, entry->s->version,
entry->in_use->thread_id, entry->db_stat ? 1 : 0,
lock_descriptions[(int)entry->reginfo.lock_type]);
}
else
{
unused++;
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
entry->s->db.str, entry->s->table_name.str, entry->s->version,
0L, entry->db_stat ? 1 : 0, "Not in use");
}
}
}
tdc_it.deinit();
......
......@@ -2859,11 +2859,22 @@ static Sys_var_ulong Sys_table_def_size(
VALID_RANGE(TABLE_DEF_CACHE_MIN, 512*1024),
DEFAULT(TABLE_DEF_CACHE_DEFAULT), BLOCK_SIZE(1));
static bool fix_table_open_cache(sys_var *, THD *, enum_var_type)
{
mysql_mutex_unlock(&LOCK_global_system_variables);
tc_purge();
mysql_mutex_lock(&LOCK_global_system_variables);
return false;
}
static Sys_var_ulong Sys_table_cache_size(
"table_open_cache", "The number of cached open tables",
GLOBAL_VAR(tc_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, 512*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT),
BLOCK_SIZE(1));
BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_table_open_cache));
static Sys_var_ulong Sys_thread_cache_size(
"thread_cache_size",
......
......@@ -3817,7 +3817,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
if (gvisitor->m_lock_open_count++ == 0)
mysql_mutex_lock(&LOCK_open);
TABLE_list::Iterator tables_it(tdc.used_tables);
All_share_tables_list::Iterator tables_it(tdc.all_tables);
/*
In case of multiple searches running in parallel, avoid going
......@@ -3835,7 +3835,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
while ((table= tables_it++))
{
if (gvisitor->inspect_edge(&table->in_use->mdl_context))
if (table->in_use && gvisitor->inspect_edge(&table->in_use->mdl_context))
{
goto end_leave_node;
}
......@@ -3844,7 +3844,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
tables_it.rewind();
while ((table= tables_it++))
{
if (table->in_use->mdl_context.visit_subgraph(gvisitor))
if (table->in_use && table->in_use->mdl_context.visit_subgraph(gvisitor))
{
goto end_leave_node;
}
......
......@@ -479,6 +479,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db,
struct TABLE_share;
struct All_share_tables;
extern ulong tdc_refresh_version(void);
......@@ -603,6 +604,7 @@ struct TABLE_SHARE
mysql_mutex_t LOCK_share; /* To protect TABLE_SHARE */
typedef I_P_List <TABLE, TABLE_share> TABLE_list;
typedef I_P_List <TABLE, All_share_tables> All_share_tables_list;
struct
{
/**
......@@ -619,7 +621,7 @@ struct TABLE_SHARE
Doubly-linked (back-linked) lists of used and unused TABLE objects
for this share.
*/
TABLE_list used_tables;
All_share_tables_list all_tables;
TABLE_list free_tables;
} tdc;
......@@ -1014,8 +1016,10 @@ struct TABLE
One should use methods of I_P_List template instead.
*/
TABLE *share_next, **share_prev;
TABLE *share_all_next, **share_all_prev;
friend struct TABLE_share;
friend struct All_share_tables;
public:
......@@ -1379,6 +1383,19 @@ struct TABLE_share
};
struct All_share_tables
{
static inline TABLE **next_ptr(TABLE *l)
{
return &l->share_all_next;
}
static inline TABLE ***prev_ptr(TABLE *l)
{
return &l->share_all_prev;
}
};
enum enum_schema_table_state
{
NOT_PROCESSED= 0,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment