summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sanja@montyprogram.com>2012-07-13 22:17:32 +0300
committerunknown <sanja@montyprogram.com>2012-07-13 22:17:32 +0300
commit9f6a1c5842fc8f71463d48e4da4ec692aadeacc1 (patch)
treefd7a7367d091702d3081ef719125c038ddc4cfb0 /sql
parent718bbcbfd0dd1aa858e4e3ba0583e85d81414df0 (diff)
downloadmariadb-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.cc116
-rw-r--r--sql/ha_partition.h26
-rw-r--r--sql/handler.h42
-rw-r--r--sql/sql_cache.cc94
-rw-r--r--sql/sql_cache.h31
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);