mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Move table cache private functions out of header
This is mostly needed to hide all references to free_tables, so that further implementation of multi-instance list can be done completely inside table_cache.cc
This commit is contained in:
@ -83,14 +83,14 @@ static int32 tc_count; /**< Number of TABLE objects in table cache. */
|
|||||||
static mysql_mutex_t LOCK_unused_shares;
|
static mysql_mutex_t LOCK_unused_shares;
|
||||||
|
|
||||||
#ifdef HAVE_PSI_INTERFACE
|
#ifdef HAVE_PSI_INTERFACE
|
||||||
PSI_mutex_key key_LOCK_unused_shares, key_TABLE_SHARE_LOCK_table_share;
|
static PSI_mutex_key key_LOCK_unused_shares, key_TABLE_SHARE_LOCK_table_share;
|
||||||
static PSI_mutex_info all_tc_mutexes[]=
|
static PSI_mutex_info all_tc_mutexes[]=
|
||||||
{
|
{
|
||||||
{ &key_LOCK_unused_shares, "LOCK_unused_shares", PSI_FLAG_GLOBAL },
|
{ &key_LOCK_unused_shares, "LOCK_unused_shares", PSI_FLAG_GLOBAL },
|
||||||
{ &key_TABLE_SHARE_LOCK_table_share, "TABLE_SHARE::tdc.LOCK_table_share", 0 }
|
{ &key_TABLE_SHARE_LOCK_table_share, "TABLE_SHARE::tdc.LOCK_table_share", 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
PSI_cond_key key_TABLE_SHARE_COND_release;
|
static PSI_cond_key key_TABLE_SHARE_COND_release;
|
||||||
static PSI_cond_info all_tc_conds[]=
|
static PSI_cond_info all_tc_conds[]=
|
||||||
{
|
{
|
||||||
{ &key_TABLE_SHARE_COND_release, "TABLE_SHARE::tdc.COND_release", 0 }
|
{ &key_TABLE_SHARE_COND_release, "TABLE_SHARE::tdc.COND_release", 0 }
|
||||||
@ -138,6 +138,19 @@ uint tc_records(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Wait for MDL deadlock detector to complete traversing tdc.all_tables.
|
||||||
|
|
||||||
|
Must be called before updating TABLE_SHARE::tdc.all_tables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void tc_wait_for_mdl_deadlock_detector(TDC_element *element)
|
||||||
|
{
|
||||||
|
while (element->all_tables_refs)
|
||||||
|
mysql_cond_wait(&element->COND_release, &element->LOCK_table_share);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove TABLE object from table cache.
|
Remove TABLE object from table cache.
|
||||||
|
|
||||||
@ -153,12 +166,12 @@ static void tc_remove_table(TABLE *table)
|
|||||||
|
|
||||||
|
|
||||||
static void tc_remove_all_unused_tables(TDC_element *element,
|
static void tc_remove_all_unused_tables(TDC_element *element,
|
||||||
TABLE_list *purge_tables,
|
TDC_element::TABLE_list *purge_tables,
|
||||||
bool mark_flushed)
|
bool mark_flushed)
|
||||||
{
|
{
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
|
|
||||||
element->wait_for_mdl_deadlock_detector();
|
tc_wait_for_mdl_deadlock_detector(element);
|
||||||
/*
|
/*
|
||||||
Mark share flushed in order to ensure that it gets
|
Mark share flushed in order to ensure that it gets
|
||||||
automatically deleted once it is no longer referenced.
|
automatically deleted once it is no longer referenced.
|
||||||
@ -220,6 +233,20 @@ void tc_purge(bool mark_flushed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get last element of free_tables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static TABLE *tc_free_tables_back(TDC_element *element)
|
||||||
|
{
|
||||||
|
TDC_element::TABLE_list::Iterator it(element->free_tables);
|
||||||
|
TABLE *entry, *last= 0;
|
||||||
|
while ((entry= it++))
|
||||||
|
last= entry;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Add new TABLE object to table cache.
|
Add new TABLE object to table cache.
|
||||||
|
|
||||||
@ -244,12 +271,12 @@ struct tc_add_table_arg
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
my_bool tc_add_table_callback(TDC_element *element, tc_add_table_arg *arg)
|
static my_bool tc_add_table_callback(TDC_element *element, tc_add_table_arg *arg)
|
||||||
{
|
{
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
|
|
||||||
mysql_mutex_lock(&element->LOCK_table_share);
|
mysql_mutex_lock(&element->LOCK_table_share);
|
||||||
if ((table= element->free_tables_back()) && table->tc_time < arg->purge_time)
|
if ((table= tc_free_tables_back(element)) && table->tc_time < arg->purge_time)
|
||||||
{
|
{
|
||||||
memcpy(arg->key, element->m_key, element->m_key_length);
|
memcpy(arg->key, element->m_key, element->m_key_length);
|
||||||
arg->key_length= element->m_key_length;
|
arg->key_length= element->m_key_length;
|
||||||
@ -265,7 +292,7 @@ void tc_add_table(THD *thd, TABLE *table)
|
|||||||
bool need_purge;
|
bool need_purge;
|
||||||
DBUG_ASSERT(table->in_use == thd);
|
DBUG_ASSERT(table->in_use == thd);
|
||||||
mysql_mutex_lock(&table->s->tdc->LOCK_table_share);
|
mysql_mutex_lock(&table->s->tdc->LOCK_table_share);
|
||||||
table->s->tdc->wait_for_mdl_deadlock_detector();
|
tc_wait_for_mdl_deadlock_detector(table->s->tdc);
|
||||||
table->s->tdc->all_tables.push_front(table);
|
table->s->tdc->all_tables.push_front(table);
|
||||||
mysql_mutex_unlock(&table->s->tdc->LOCK_table_share);
|
mysql_mutex_unlock(&table->s->tdc->LOCK_table_share);
|
||||||
|
|
||||||
@ -290,14 +317,14 @@ void tc_add_table(THD *thd, TABLE *table)
|
|||||||
TABLE *entry;
|
TABLE *entry;
|
||||||
mysql_mutex_lock(&element->LOCK_table_share);
|
mysql_mutex_lock(&element->LOCK_table_share);
|
||||||
lf_hash_search_unpin(thd->tdc_hash_pins);
|
lf_hash_search_unpin(thd->tdc_hash_pins);
|
||||||
element->wait_for_mdl_deadlock_detector();
|
tc_wait_for_mdl_deadlock_detector(element);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
It may happen that oldest table was acquired meanwhile. In this case
|
It may happen that oldest table was acquired meanwhile. In this case
|
||||||
just go ahead, number of objects in table cache will normalize
|
just go ahead, number of objects in table cache will normalize
|
||||||
eventually.
|
eventually.
|
||||||
*/
|
*/
|
||||||
if ((entry= element->free_tables_back()) &&
|
if ((entry= tc_free_tables_back(element)) &&
|
||||||
entry->tc_time == argument.purge_time)
|
entry->tc_time == argument.purge_time)
|
||||||
{
|
{
|
||||||
element->free_tables.remove(entry);
|
element->free_tables.remove(entry);
|
||||||
@ -313,6 +340,36 @@ void tc_add_table(THD *thd, TABLE *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Acquire TABLE object from table cache.
|
||||||
|
|
||||||
|
@pre share must be protected against removal.
|
||||||
|
|
||||||
|
Acquired object cannot be evicted or acquired again.
|
||||||
|
|
||||||
|
@return TABLE object, or NULL if no unused objects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static TABLE *tc_acquire_table(THD *thd, TDC_element *element)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
|
||||||
|
mysql_mutex_lock(&element->LOCK_table_share);
|
||||||
|
table= element->free_tables.pop_front();
|
||||||
|
if (table)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!table->in_use);
|
||||||
|
table->in_use= thd;
|
||||||
|
/* The ex-unused table must be fully functional. */
|
||||||
|
DBUG_ASSERT(table->db_stat && table->file);
|
||||||
|
/* The children must be detached from the table. */
|
||||||
|
DBUG_ASSERT(!table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Release TABLE object to table cache.
|
Release TABLE object to table cache.
|
||||||
|
|
||||||
@ -368,7 +425,7 @@ bool tc_release_table(TABLE *table)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
purge:
|
purge:
|
||||||
table->s->tdc->wait_for_mdl_deadlock_detector();
|
tc_wait_for_mdl_deadlock_detector(table->s->tdc);
|
||||||
tc_remove_table(table);
|
tc_remove_table(table);
|
||||||
mysql_mutex_unlock(&table->s->tdc->LOCK_table_share);
|
mysql_mutex_unlock(&table->s->tdc->LOCK_table_share);
|
||||||
table->in_use= 0;
|
table->in_use= 0;
|
||||||
@ -377,6 +434,19 @@ purge:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void tdc_assert_clean_share(TDC_element *element)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(element->share == 0);
|
||||||
|
DBUG_ASSERT(element->ref_count == 0);
|
||||||
|
DBUG_ASSERT(element->m_flush_tickets.is_empty());
|
||||||
|
DBUG_ASSERT(element->all_tables.is_empty());
|
||||||
|
DBUG_ASSERT(element->free_tables.is_empty());
|
||||||
|
DBUG_ASSERT(element->all_tables_refs == 0);
|
||||||
|
DBUG_ASSERT(element->next == 0);
|
||||||
|
DBUG_ASSERT(element->prev == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Delete share from hash and free share object.
|
Delete share from hash and free share object.
|
||||||
*/
|
*/
|
||||||
@ -419,7 +489,7 @@ static void tdc_delete_share_from_hash(TDC_element *element)
|
|||||||
pins= lf_hash_get_pins(&tdc_hash);
|
pins= lf_hash_get_pins(&tdc_hash);
|
||||||
|
|
||||||
DBUG_ASSERT(pins); // What can we do about it?
|
DBUG_ASSERT(pins); // What can we do about it?
|
||||||
element->assert_clean_share();
|
tdc_assert_clean_share(element);
|
||||||
lf_hash_delete(&tdc_hash, pins, element->m_key, element->m_key_length);
|
lf_hash_delete(&tdc_hash, pins, element->m_key, element->m_key_length);
|
||||||
if (!thd)
|
if (!thd)
|
||||||
lf_hash_put_pins(pins);
|
lf_hash_put_pins(pins);
|
||||||
@ -428,6 +498,61 @@ static void tdc_delete_share_from_hash(TDC_element *element)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Prepeare table share for use with table definition cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void lf_alloc_constructor(uchar *arg)
|
||||||
|
{
|
||||||
|
TDC_element *element= (TDC_element*) (arg + LF_HASH_OVERHEAD);
|
||||||
|
DBUG_ENTER("lf_alloc_constructor");
|
||||||
|
mysql_mutex_init(key_TABLE_SHARE_LOCK_table_share,
|
||||||
|
&element->LOCK_table_share, MY_MUTEX_INIT_FAST);
|
||||||
|
mysql_cond_init(key_TABLE_SHARE_COND_release, &element->COND_release, 0);
|
||||||
|
element->m_flush_tickets.empty();
|
||||||
|
element->all_tables.empty();
|
||||||
|
element->free_tables.empty();
|
||||||
|
element->all_tables_refs= 0;
|
||||||
|
element->share= 0;
|
||||||
|
element->ref_count= 0;
|
||||||
|
element->next= 0;
|
||||||
|
element->prev= 0;
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Release table definition cache specific resources of table share.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void lf_alloc_destructor(uchar *arg)
|
||||||
|
{
|
||||||
|
TDC_element *element= (TDC_element*) (arg + LF_HASH_OVERHEAD);
|
||||||
|
DBUG_ENTER("lf_alloc_destructor");
|
||||||
|
tdc_assert_clean_share(element);
|
||||||
|
mysql_cond_destroy(&element->COND_release);
|
||||||
|
mysql_mutex_destroy(&element->LOCK_table_share);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void tdc_hash_initializer(LF_HASH *hash __attribute__((unused)),
|
||||||
|
TDC_element *element, LEX_STRING *key)
|
||||||
|
{
|
||||||
|
memcpy(element->m_key, key->str, key->length);
|
||||||
|
element->m_key_length= key->length;
|
||||||
|
tdc_assert_clean_share(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uchar *tdc_hash_key(const TDC_element *element, size_t *length,
|
||||||
|
my_bool not_used __attribute__((unused)))
|
||||||
|
{
|
||||||
|
*length= element->m_key_length;
|
||||||
|
return (uchar*) element->m_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initialize table definition cache.
|
Initialize table definition cache.
|
||||||
*/
|
*/
|
||||||
@ -443,11 +568,11 @@ void tdc_init(void)
|
|||||||
MY_MUTEX_INIT_FAST);
|
MY_MUTEX_INIT_FAST);
|
||||||
tdc_version= 1L; /* Increments on each reload */
|
tdc_version= 1L; /* Increments on each reload */
|
||||||
lf_hash_init(&tdc_hash, sizeof(TDC_element), LF_HASH_UNIQUE, 0, 0,
|
lf_hash_init(&tdc_hash, sizeof(TDC_element), LF_HASH_UNIQUE, 0, 0,
|
||||||
(my_hash_get_key) TDC_element::key,
|
(my_hash_get_key) tdc_hash_key,
|
||||||
&my_charset_bin);
|
&my_charset_bin);
|
||||||
tdc_hash.alloc.constructor= TDC_element::lf_alloc_constructor;
|
tdc_hash.alloc.constructor= lf_alloc_constructor;
|
||||||
tdc_hash.alloc.destructor= TDC_element::lf_alloc_destructor;
|
tdc_hash.alloc.destructor= lf_alloc_destructor;
|
||||||
tdc_hash.initializer= (lf_hash_initializer) TDC_element::lf_hash_initializer;
|
tdc_hash.initializer= (lf_hash_initializer) tdc_hash_initializer;
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,7 +806,7 @@ retry:
|
|||||||
|
|
||||||
if (out_table && (flags & GTS_TABLE))
|
if (out_table && (flags & GTS_TABLE))
|
||||||
{
|
{
|
||||||
if ((*out_table= element->acquire_table(thd)))
|
if ((*out_table= tc_acquire_table(thd, element)))
|
||||||
{
|
{
|
||||||
lf_hash_search_unpin(thd->tdc_hash_pins);
|
lf_hash_search_unpin(thd->tdc_hash_pins);
|
||||||
DBUG_ASSERT(!(flags & GTS_NOLOCK));
|
DBUG_ASSERT(!(flags & GTS_NOLOCK));
|
||||||
|
@ -16,14 +16,8 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_PSI_INTERFACE
|
struct TDC_element
|
||||||
extern PSI_mutex_key key_TABLE_SHARE_LOCK_table_share;
|
|
||||||
extern PSI_cond_key key_TABLE_SHARE_COND_release;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class TDC_element
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
uchar m_key[NAME_LEN + 1 + NAME_LEN + 1];
|
uchar m_key[NAME_LEN + 1 + NAME_LEN + 1];
|
||||||
uint m_key_length;
|
uint m_key_length;
|
||||||
ulong version;
|
ulong version;
|
||||||
@ -53,138 +47,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
All_share_tables_list all_tables;
|
All_share_tables_list all_tables;
|
||||||
TABLE_list free_tables;
|
TABLE_list free_tables;
|
||||||
|
|
||||||
TDC_element() {}
|
|
||||||
|
|
||||||
TDC_element(const char *key_arg, uint key_length) : m_key_length(key_length)
|
|
||||||
{
|
|
||||||
memcpy(m_key, key_arg, key_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void assert_clean_share()
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(share == 0);
|
|
||||||
DBUG_ASSERT(ref_count == 0);
|
|
||||||
DBUG_ASSERT(m_flush_tickets.is_empty());
|
|
||||||
DBUG_ASSERT(all_tables.is_empty());
|
|
||||||
DBUG_ASSERT(free_tables.is_empty());
|
|
||||||
DBUG_ASSERT(all_tables_refs == 0);
|
|
||||||
DBUG_ASSERT(next == 0);
|
|
||||||
DBUG_ASSERT(prev == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Acquire TABLE object from table cache.
|
|
||||||
|
|
||||||
@pre share must be protected against removal.
|
|
||||||
|
|
||||||
Acquired object cannot be evicted or acquired again.
|
|
||||||
|
|
||||||
@return TABLE object, or NULL if no unused objects.
|
|
||||||
*/
|
|
||||||
|
|
||||||
TABLE *acquire_table(THD *thd)
|
|
||||||
{
|
|
||||||
TABLE *table;
|
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_table_share);
|
|
||||||
table= free_tables.pop_front();
|
|
||||||
if (table)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(!table->in_use);
|
|
||||||
table->in_use= thd;
|
|
||||||
/* The ex-unused table must be fully functional. */
|
|
||||||
DBUG_ASSERT(table->db_stat && table->file);
|
|
||||||
/* The children must be detached from the table. */
|
|
||||||
DBUG_ASSERT(!table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
|
|
||||||
}
|
|
||||||
mysql_mutex_unlock(&LOCK_table_share);
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get last element of free_tables.
|
|
||||||
*/
|
|
||||||
|
|
||||||
TABLE *free_tables_back()
|
|
||||||
{
|
|
||||||
TABLE_list::Iterator it(free_tables);
|
|
||||||
TABLE *entry, *last= 0;
|
|
||||||
while ((entry= it++))
|
|
||||||
last= entry;
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Wait for MDL deadlock detector to complete traversing tdc.all_tables.
|
|
||||||
|
|
||||||
Must be called before updating TABLE_SHARE::tdc.all_tables.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void wait_for_mdl_deadlock_detector()
|
|
||||||
{
|
|
||||||
while (all_tables_refs)
|
|
||||||
mysql_cond_wait(&COND_release, &LOCK_table_share);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Prepeare table share for use with table definition cache.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void lf_alloc_constructor(uchar *arg)
|
|
||||||
{
|
|
||||||
TDC_element *element= (TDC_element*) (arg + LF_HASH_OVERHEAD);
|
|
||||||
DBUG_ENTER("lf_alloc_constructor");
|
|
||||||
mysql_mutex_init(key_TABLE_SHARE_LOCK_table_share,
|
|
||||||
&element->LOCK_table_share, MY_MUTEX_INIT_FAST);
|
|
||||||
mysql_cond_init(key_TABLE_SHARE_COND_release, &element->COND_release, 0);
|
|
||||||
element->m_flush_tickets.empty();
|
|
||||||
element->all_tables.empty();
|
|
||||||
element->free_tables.empty();
|
|
||||||
element->all_tables_refs= 0;
|
|
||||||
element->share= 0;
|
|
||||||
element->ref_count= 0;
|
|
||||||
element->next= 0;
|
|
||||||
element->prev= 0;
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Release table definition cache specific resources of table share.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void lf_alloc_destructor(uchar *arg)
|
|
||||||
{
|
|
||||||
TDC_element *element= (TDC_element*) (arg + LF_HASH_OVERHEAD);
|
|
||||||
DBUG_ENTER("lf_alloc_destructor");
|
|
||||||
element->assert_clean_share();
|
|
||||||
mysql_cond_destroy(&element->COND_release);
|
|
||||||
mysql_mutex_destroy(&element->LOCK_table_share);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void lf_hash_initializer(LF_HASH *hash __attribute__((unused)),
|
|
||||||
TDC_element *element, LEX_STRING *key)
|
|
||||||
{
|
|
||||||
memcpy(element->m_key, key->str, key->length);
|
|
||||||
element->m_key_length= key->length;
|
|
||||||
element->assert_clean_share();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uchar *key(const TDC_element *element, size_t *length,
|
|
||||||
my_bool not_used __attribute__((unused)))
|
|
||||||
{
|
|
||||||
*length= element->m_key_length;
|
|
||||||
return (uchar*) element->m_key;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user