diff options
author | unknown <sanja@montyprogram.com> | 2012-07-13 22:17:32 +0300 |
---|---|---|
committer | unknown <sanja@montyprogram.com> | 2012-07-13 22:17:32 +0300 |
commit | 9f6a1c5842fc8f71463d48e4da4ec692aadeacc1 (patch) | |
tree | fd7a7367d091702d3081ef719125c038ddc4cfb0 /sql | |
parent | 718bbcbfd0dd1aa858e4e3ba0583e85d81414df0 (diff) | |
download | mariadb-git-9f6a1c5842fc8f71463d48e4da4ec692aadeacc1.tar.gz |
fixed MySQL bug#53775:
Now partition engine adds underlying tables to the QC and ask underlying tables engine permittion to cache the query and return result of the query.
Incorrect QC cleanup in case of table registration failure fixe.
Unified interface for myisammrg & partitioned engnes for QC.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_partition.cc | 116 | ||||
-rw-r--r-- | sql/ha_partition.h | 26 | ||||
-rw-r--r-- | sql/handler.h | 42 | ||||
-rw-r--r-- | sql/sql_cache.cc | 94 | ||||
-rw-r--r-- | sql/sql_cache.h | 31 |
5 files changed, 225 insertions, 84 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b4181fc6d7f..7c2ffeb1b44 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2076,6 +2076,122 @@ partition_element *ha_partition::find_partition_element(uint part_id) return NULL; } +uint ha_partition::count_query_cache_dependant_tables(uint8 *tables_type) +{ + DBUG_ENTER("ha_partition::count_query_cache_dependant_tables"); + /* Here we rely on the fact that all tables are of the same type */ + (*tables_type)|= m_file[0]->table_cache_type(); + DBUG_PRINT("info", ("cnt: %u", (uint)m_tot_parts)); + DBUG_RETURN(m_tot_parts); +} + +my_bool ha_partition::reg_query_cache_dependant_table(THD *thd, + char *key, uint key_len, + uint8 type, + Query_cache *cache, + Query_cache_block_table **block_table, + handler *file, + uint *n) +{ + DBUG_ENTER("ha_partition::reg_query_cache_dependant_table"); + qc_engine_callback engine_callback; + ulonglong engine_data; + /* ask undelying engine */ + if (!file->register_query_cache_table(thd, key, + key_len, + &engine_callback, + &engine_data)) + { + DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s", + key, + key + table_share->db.length + 1)); + /* + As this can change from call to call, don't reset set + thd->lex->safe_to_cache_query + */ + thd->query_cache_is_applicable= 0; // Query can't be cached + DBUG_RETURN(TRUE); + } + (++(*block_table))->n= ++(*n); + if (!cache->insert_table(key_len, + key, (*block_table), + table_share->db.length, + type, + engine_callback, engine_data, + FALSE)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + + +my_bool ha_partition::register_query_cache_dependant_tables(THD *thd, + Query_cache *cache, + Query_cache_block_table **block_table, + uint *n) +{ + char *name; + uint prefix_length= table_share->table_cache_key.length + 3; + uint num_parts= m_part_info->num_parts; + uint num_subparts= m_part_info->num_subparts; + uint i= 0; + List_iterator<partition_element> part_it(m_part_info->partitions); + char key[FN_REFLEN]; + + DBUG_ENTER("ha_partition::register_query_cache_dependant_tables"); + + /* prepare static part of the key */ + memmove(key, table_share->table_cache_key.str, + table_share->table_cache_key.length); + + name= key + table_share->table_cache_key.length - 1; + name[0]= name[2]= '#'; + name[1]= 'P'; + name+= 3; + + do + { + partition_element *part_elem= part_it++; + uint part_len= strmov(name, part_elem->partition_name) - name; + if (m_is_sub_partitioned) + { + List_iterator<partition_element> subpart_it(part_elem->subpartitions); + partition_element *sub_elem; + char *sname= name + part_len; + uint j= 0, part; + sname[0]= sname[3]= '#'; + sname[1]= 'S'; + sname[2]= 'P'; + sname += 4; + do + { + sub_elem= subpart_it++; + part= i * num_subparts + j; + uint spart_len= strmov(sname, sub_elem->partition_name) - name + 1; + if (reg_query_cache_dependant_table(thd, key, + prefix_length + part_len + 4 + + spart_len, + m_file[part]->table_cache_type(), + cache, + block_table, m_file[part], + n)) + DBUG_RETURN(TRUE); + } while (++j < num_subparts); + } + else + { + if (reg_query_cache_dependant_table(thd, key, + prefix_length + part_len + 1, + m_file[i]->table_cache_type(), + cache, + block_table, m_file[i], + n)) + DBUG_RETURN(TRUE); + } + } while (++i < num_parts); + DBUG_PRINT("info", ("cnt: %u", (uint)m_tot_parts)); + DBUG_RETURN(FALSE); +} + /* Set up table share object before calling create on underlying handler diff --git a/sql/ha_partition.h b/sql/ha_partition.h index aa9179f9f69..0f922394ec5 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -544,22 +544,20 @@ public: virtual int extra(enum ha_extra_function operation); virtual int extra_opt(enum ha_extra_function operation, ulong cachesize); virtual int reset(void); - /* - Do not allow caching of partitioned tables, since we cannot return - a callback or engine_data that would work for a generic engine. - */ - virtual my_bool register_query_cache_table(THD *thd, char *table_key, - uint key_length, - qc_engine_callback - *engine_callback, - ulonglong *engine_data) - { - *engine_callback= NULL; - *engine_data= 0; - return FALSE; - } + virtual uint count_query_cache_dependant_tables(uint8 *tables_type); + virtual my_bool + register_query_cache_dependant_tables(THD *thd, + Query_cache *cache, + Query_cache_block_table **block, + uint *n); private: + my_bool reg_query_cache_dependant_table(THD *thd, + char *key, uint key_len, uint8 type, + Query_cache *cache, + Query_cache_block_table + **block_table, + handler *file, uint *n); static const uint NO_CURRENT_PART_ID; int loop_extra(enum ha_extra_function operation); void late_extra_cache(uint partition_id); diff --git a/sql/handler.h b/sql/handler.h index ee1731af563..217c8103cd7 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1689,6 +1689,8 @@ public: virtual ~handler_add_index() {} }; +class Query_cache; +class Query_cache_block_table; /** The handler class is the interface for dynamically loadable storage engines. Do not add ifdefs and take care when adding or @@ -2522,6 +2524,46 @@ public: return TRUE; } + /* + Count tables invisible from all tables list on which current one built + (like myisammrg and partitioned tables) + + tables_type mask for the tables should be added herdde + + returns number of such tables + */ + + virtual uint count_query_cache_dependant_tables(uint8 *tables_type + __attribute__((unused))) + { + return 0; + } + + /* + register tables invisible from all tables list on which current one built + (like myisammrg and partitioned tables). + + @note they should be counted by method above + + cache Query cache pointer + block Query cache block to write the table + n Number of the table + + @retval FALSE - OK + @retval TRUE - Error + */ + + virtual my_bool + register_query_cache_dependant_tables(THD *thd + __attribute__((unused)), + Query_cache *cache + __attribute__((unused)), + Query_cache_block_table **block + __attribute__((unused)), + uint *n __attribute__((unused))) + { + return FALSE; + } /* Check if the primary key (if there is one) is a clustered and a diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 96814562757..7edd28446a2 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1533,7 +1533,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", unlock(); goto end; } - if (!register_all_tables(query_block, tables_used, local_tables)) + if (!register_all_tables(thd, query_block, tables_used, local_tables)) { refused++; DBUG_PRINT("warning", ("tables list including failed")); @@ -3203,6 +3203,7 @@ Query_cache::invalidate_query_block_list(THD *thd, SYNOPSIS Query_cache::register_tables_from_list + thd thread handle tables_used given table list counter number current position in table of tables of block block_table pointer to current position in tables table of block @@ -3213,24 +3214,24 @@ Query_cache::invalidate_query_block_list(THD *thd, */ TABLE_COUNTER_TYPE -Query_cache::register_tables_from_list(TABLE_LIST *tables_used, +Query_cache::register_tables_from_list(THD *thd, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE counter, - Query_cache_block_table *block_table) + Query_cache_block_table **block_table) { TABLE_COUNTER_TYPE n; DBUG_ENTER("Query_cache::register_tables_from_list"); for (n= counter; tables_used; - tables_used= tables_used->next_global, n++, block_table++) + tables_used= tables_used->next_global, n++, (*block_table)++) { if (tables_used->is_anonymous_derived_table()) { DBUG_PRINT("qcache", ("derived table skipped")); n--; - block_table--; + (*block_table)--; continue; } - block_table->n= n; + (*block_table)->n= n; if (tables_used->view) { char key[MAX_DBKEY_LENGTH]; @@ -3243,9 +3244,9 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, /* There are not callback function for for VIEWs */ - if (!insert_table(key_length, key, block_table, + if (!insert_table(key_length, key, (*block_table), tables_used->view_db.length + 1, - HA_CACHE_TBL_NONTRANSACT, 0, 0)) + HA_CACHE_TBL_NONTRANSACT, 0, 0, TRUE)) DBUG_RETURN(0); /* We do not need to register view tables here because they are already @@ -3264,42 +3265,17 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, if (!insert_table(tables_used->table->s->table_cache_key.length, tables_used->table->s->table_cache_key.str, - block_table, + (*block_table), tables_used->db_length, tables_used->table->file->table_cache_type(), tables_used->callback_func, - tables_used->engine_data)) + tables_used->engine_data, + TRUE)) DBUG_RETURN(0); -#ifdef WITH_MYISAMMRG_STORAGE_ENGINE - /* - XXX FIXME: Some generic mechanism is required here instead of this - MYISAMMRG-specific implementation. - */ - if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM) - { - ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file; - MYRG_INFO *file = handler->myrg_info(); - for (MYRG_TABLE *table = file->open_tables; - table != file->end_table ; - table++) - { - char key[MAX_DBKEY_LENGTH]; - uint32 db_length; - uint key_length= filename_2_table_key(key, table->table->filename, - &db_length); - (++block_table)->n= ++n; - /* - There are not callback function for for MyISAM, and engine data - */ - if (!insert_table(key_length, key, block_table, - db_length, - tables_used->table->file->table_cache_type(), - 0, 0)) - DBUG_RETURN(0); - } - } -#endif + if (tables_used->table->file-> + register_query_cache_dependant_tables(thd, this, block_table, &n)) + DBUG_RETURN(0); } } DBUG_RETURN(n - counter); @@ -3310,12 +3286,14 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, SYNOPSIS register_all_tables() + thd Thread handle block Store tables in this block tables_used List if used tables tables_arg Not used ? */ -my_bool Query_cache::register_all_tables(Query_cache_block *block, +my_bool Query_cache::register_all_tables(THD *thd, + Query_cache_block *block, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE tables_arg) { @@ -3326,7 +3304,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, Query_cache_block_table *block_table = block->table(0); - n= register_tables_from_list(tables_used, 0, block_table); + n= register_tables_from_list(thd, tables_used, 0, &block_table); if (n==0) { @@ -3335,6 +3313,8 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, tmp != block_table; tmp++) unlink_table(tmp); + if (block_table->parent) + unlink_table(block_table); } return test(n); } @@ -3353,7 +3333,8 @@ Query_cache::insert_table(uint key_len, char *key, Query_cache_block_table *node, uint32 db_length, uint8 cache_type, qc_engine_callback callback, - ulonglong engine_data) + ulonglong engine_data, + my_bool hash) { DBUG_ENTER("Query_cache::insert_table"); DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d", @@ -3361,8 +3342,10 @@ Query_cache::insert_table(uint key_len, char *key, THD *thd= current_thd; - Query_cache_block *table_block= - (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len); + Query_cache_block *table_block= + (hash ? + (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len) : + NULL); if (table_block && table_block->table()->engine_data() != engine_data) @@ -3412,7 +3395,8 @@ Query_cache::insert_table(uint key_len, char *key, */ list_root->next= list_root->prev= list_root; - if (my_hash_insert(&tables, (const uchar *) table_block)) + if (hash && + my_hash_insert(&tables, (const uchar *) table_block)) { DBUG_PRINT("qcache", ("Can't insert table to hash")); // write_block_data return locked block @@ -3425,6 +3409,7 @@ Query_cache::insert_table(uint key_len, char *key, header->type(cache_type); header->callback(callback); header->engine_data(engine_data); + header->set_hashed(hash); /* We insert this table without the assumption that it isn't refrenenced by @@ -3478,7 +3463,9 @@ void Query_cache::unlink_table(Query_cache_block_table *node) Query_cache_block *table_block= neighbour->block(); double_linked_list_exclude(table_block, &tables_blocks); - my_hash_delete(&tables,(uchar *) table_block); + Query_cache_table *header= table_block->table(); + if (header->is_hashed()) + my_hash_delete(&tables,(uchar *) table_block); free_memory_block(table_block); } DBUG_VOID_RETURN; @@ -3951,6 +3938,9 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, table_alias_charset used here because it depends of lower_case_table_names variable */ + table_count+= tables_used->table->file-> + count_query_cache_dependant_tables(tables_type); + if (tables_used->table->s->tmp_table != NO_TMP_TABLE || (*tables_type & HA_CACHE_TBL_NOCACHE) || (tables_used->db_length == 5 && @@ -3963,18 +3953,6 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, "other non-cacheable table(s)")); DBUG_RETURN(0); } -#ifdef WITH_MYISAMMRG_STORAGE_ENGINE - /* - XXX FIXME: Some generic mechanism is required here instead of this - MYISAMMRG-specific implementation. - */ - if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM) - { - ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file; - MYRG_INFO *file = handler->myrg_info(); - table_count+= (file->end_table - file->open_tables); - } -#endif } } DBUG_RETURN(table_count); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 87291e80a85..7444d444cf9 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -200,6 +200,10 @@ struct Query_cache_table The number of queries depending of this table. */ int32 m_cached_query_count; + /** + If table included in the table hash to be found by other queries + */ + my_bool hashed; inline char *db() { return (char *) data(); } inline char *table() { return tbl; } @@ -212,6 +216,8 @@ struct Query_cache_table inline void callback(qc_engine_callback fn){ callback_func= fn; } inline ulonglong engine_data() { return engine_data_buff; } inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } + inline my_bool is_hashed() { return hashed; } + inline void set_hashed(my_bool hash) { hashed= hash; } inline uchar* data() { return (uchar*)(((uchar*)this)+ @@ -343,10 +349,6 @@ protected: static void double_linked_list_join(Query_cache_block *head_tail, Query_cache_block *tail_head); - /* Table key generation */ - static uint filename_2_table_key (char *key, const char *filename, - uint32 *db_langth); - /* The following functions require that structure_guard_mutex is locked */ void flush_cache(); my_bool free_old_query(); @@ -363,17 +365,12 @@ protected: Query_cache_block_table *list_root); TABLE_COUNTER_TYPE - register_tables_from_list(TABLE_LIST *tables_used, + register_tables_from_list(THD *thd, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE counter, - Query_cache_block_table *block_table); - my_bool register_all_tables(Query_cache_block *block, + Query_cache_block_table **block_table); + my_bool register_all_tables(THD *thd, Query_cache_block *block, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE tables); - my_bool insert_table(uint key_len, char *key, - Query_cache_block_table *node, - uint32 db_length, uint8 cache_type, - qc_engine_callback callback, - ulonglong engine_data); void unlink_table(Query_cache_block_table *node); Query_cache_block *get_free_block (ulong len, my_bool not_less, ulong min); @@ -491,6 +488,12 @@ protected: const char *packet, ulong length, unsigned pkt_nr); + my_bool insert_table(uint key_len, char *key, + Query_cache_block_table *node, + uint32 db_length, uint8 cache_type, + qc_engine_callback callback, + ulonglong engine_data, + my_bool hash); void end_of_result(THD *thd); void abort(Query_cache_tls *query_cache_tls); @@ -513,6 +516,10 @@ protected: const char *name); my_bool in_blocks(Query_cache_block * point); + /* Table key generation */ + static uint filename_2_table_key (char *key, const char *filename, + uint32 *db_langth); + enum Cache_try_lock_mode {WAIT, TIMEOUT, TRY}; bool try_lock(THD *thd, Cache_try_lock_mode mode= WAIT); void lock(THD *thd); |