summaryrefslogtreecommitdiff
path: root/sql/table_cache.h
diff options
context:
space:
mode:
authorSergey Vojtovich <svoj@mariadb.org>2014-12-28 19:42:17 +0400
committerSergey Vojtovich <svoj@mariadb.org>2014-12-28 19:46:18 +0400
commit6dbc48ca79e5fdd8d4022b00b862e08a4198155b (patch)
tree1904e477f09dd958af2b6696d4b7c8dbb0a1772d /sql/table_cache.h
parent8883c54ac08a555bc7d9b09395f49893ad4d80b5 (diff)
downloadmariadb-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.h180
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);
-};