diff options
author | Sergey Vojtovich <svoj@mariadb.org> | 2014-12-28 19:42:17 +0400 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2014-12-28 19:46:18 +0400 |
commit | 6dbc48ca79e5fdd8d4022b00b862e08a4198155b (patch) | |
tree | 1904e477f09dd958af2b6696d4b7c8dbb0a1772d /sql/table_cache.h | |
parent | 8883c54ac08a555bc7d9b09395f49893ad4d80b5 (diff) | |
download | mariadb-git-6dbc48ca79e5fdd8d4022b00b862e08a4198155b.tar.gz |
MDEV-7324 - Lock-free hash for table definition cache
Diffstat (limited to 'sql/table_cache.h')
-rw-r--r-- | sql/table_cache.h | 180 |
1 files changed, 165 insertions, 15 deletions
diff --git a/sql/table_cache.h b/sql/table_cache.h index ea3822f9f68..b829e4de752 100644 --- a/sql/table_cache.h +++ b/sql/table_cache.h @@ -16,6 +16,165 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +extern PSI_mutex_key key_TABLE_SHARE_LOCK_table_share; +extern PSI_cond_key key_TABLE_SHARE_COND_release; + +class TDC_element +{ +public: + uchar m_key[NAME_LEN + 1 + NAME_LEN + 1]; + uint m_key_length; + ulong version; + bool flushed; + TABLE_SHARE *share; + + typedef I_P_List <TABLE, TABLE_share> TABLE_list; + typedef I_P_List <TABLE, All_share_tables> All_share_tables_list; + /** + Protects ref_count, m_flush_tickets, all_tables, free_tables, flushed, + all_tables_refs. + */ + mysql_mutex_t LOCK_table_share; + mysql_cond_t COND_release; + TDC_element *next, **prev; /* Link to unused shares */ + uint ref_count; /* How many TABLE objects uses this */ + uint all_tables_refs; /* Number of refs to all_tables */ + /** + List of tickets representing threads waiting for the share to be flushed. + */ + Wait_for_flush_list m_flush_tickets; + /* + Doubly-linked (back-linked) lists of used and unused TABLE objects + for this share. + */ + All_share_tables_list all_tables; + TABLE_list free_tables; + + TDC_element() {} + + TDC_element(const char *key, uint key_length) : m_key_length(key_length) + { + memcpy(m_key, key, 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(share->tdc->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 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; + } +}; + + enum enum_tdc_remove_table_type { TDC_RT_REMOVE_ALL, @@ -27,15 +186,14 @@ enum enum_tdc_remove_table_type extern ulong tdc_size; extern ulong tc_size; -extern int tdc_init(void); +extern void tdc_init(void); extern void tdc_start_shutdown(void); extern void tdc_deinit(void); extern ulong tdc_records(void); extern void tdc_purge(bool all); -extern void tdc_init_share(TABLE_SHARE *share); -extern void tdc_deinit_share(TABLE_SHARE *share); -extern TABLE_SHARE *tdc_lock_share(const char *db, const char *table_name); -extern void tdc_unlock_share(TABLE_SHARE *share); +extern TDC_element *tdc_lock_share(THD *thd, const char *db, + const char *table_name); +extern void tdc_unlock_share(TDC_element *element); extern TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db, const char *table_name, const char *key, uint key_length, @@ -52,6 +210,8 @@ extern int tdc_wait_for_old_version(THD *thd, const char *db, extern ulong tdc_refresh_version(void); extern ulong tdc_increment_refresh_version(void); extern void tdc_assign_new_table_id(TABLE_SHARE *share); +extern int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument, + bool no_dups= false); extern uint tc_records(void); extern void tc_purge(bool mark_flushed= false); @@ -125,13 +285,3 @@ static inline TABLE_SHARE *tdc_acquire_share_shortlived(THD *thd, TABLE_LIST *tl return tdc_acquire_share(thd, tl->db, tl->table_name, key, key_length, tl->mdl_request.key.tc_hash_value(), flags, 0); } - - -class TDC_iterator -{ - ulong idx; -public: - void init(void); - void deinit(void); - TABLE_SHARE *next(void); -}; |