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 | |
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.
-rw-r--r-- | mysql-test/include/query_cache_partitions.inc | 126 | ||||
-rw-r--r-- | mysql-test/r/partition_cache.result | 18 | ||||
-rw-r--r-- | mysql-test/r/partition_cache_innodb.result | 151 | ||||
-rw-r--r-- | mysql-test/r/partition_cache_myisam.result | 153 | ||||
-rw-r--r-- | mysql-test/t/partition_cache_innodb.test | 14 | ||||
-rw-r--r-- | mysql-test/t/partition_cache_myisam.test | 14 | ||||
-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 | ||||
-rw-r--r-- | storage/myisammrg/ha_myisammrg.cc | 41 | ||||
-rw-r--r-- | storage/myisammrg/ha_myisammrg.h | 6 |
13 files changed, 739 insertions, 93 deletions
diff --git a/mysql-test/include/query_cache_partitions.inc b/mysql-test/include/query_cache_partitions.inc new file mode 100644 index 00000000000..e5bb7406c10 --- /dev/null +++ b/mysql-test/include/query_cache_partitions.inc @@ -0,0 +1,126 @@ +# include/query_cache_partitions.inc +# +# The variables +# $engine_type -- storage engine to be tested +# have to be set before sourcing this script. + +eval SET SESSION STORAGE_ENGINE = $engine_type; + +# Initialise +--disable_warnings +drop table if exists t1; +--enable_warnings + +set @save_query_cache_size = @@global.query_cache_size; + +--echo # Test that partitions works with query cache + +flush query cache; + +SET GLOBAL query_cache_size=1024*1024*512; + CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `created_at` datetime NOT NULL, + `cool` tinyint default 0 + ); + + ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( + PARTITION month_2010_4 VALUES LESS THAN (734258), + PARTITION month_2010_5 VALUES LESS THAN (734289), + PARTITION month_max VALUES LESS THAN MAXVALUE + ); + +show create table t1; + +INSERT INTO t1 VALUES (1, now(), 0); + +flush status; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + + +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +drop table t1; + +--echo # Test that sub-partitions works with query cache + +flush query cache; + +SET GLOBAL query_cache_size=1024*1024*512; + CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `created_at` datetime NOT NULL, + `cool` tinyint default 0 + ) + PARTITION BY RANGE (TO_DAYS(created_at)) + subpartition by hash(cool) subpartitions 3 ( + PARTITION month_2010_4 VALUES LESS THAN (734258), + PARTITION month_2010_5 VALUES LESS THAN (734289), + PARTITION month_max VALUES LESS THAN MAXVALUE + ); + +show create table t1; + +INSERT INTO t1 VALUES (1, now(), 0); + +flush status; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +drop table t1; + +--echo # +--echo # MySQL bug#53775 Query on partitioned table returns cached result +--echo # from previous transaction +--echo # + +flush query cache; +flush status; + +SET GLOBAL query_cache_size=1024*1024*512; + CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `created_at` datetime NOT NULL, + `cool` tinyint default 0 + ); + + ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( + PARTITION month_2010_4 VALUES LESS THAN (734258), + PARTITION month_2010_5 VALUES LESS THAN (734289), + PARTITION month_max VALUES LESS THAN MAXVALUE + ); + +INSERT INTO t1 VALUES (1, now(), 0); + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +BEGIN; +UPDATE `t1` SET `cool` = 1 WHERE `id` = 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +BEGIN; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +drop table t1; + +set @@global.query_cache_size = @save_query_cache_size; diff --git a/mysql-test/r/partition_cache.result b/mysql-test/r/partition_cache.result index ac2da9bb78a..cd579d00952 100644 --- a/mysql-test/r/partition_cache.result +++ b/mysql-test/r/partition_cache.result @@ -27,7 +27,7 @@ a 3 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 drop table t1; commit; create table t1 (a int not null) PARTITION BY KEY (a) PARTITIONS 3; @@ -50,7 +50,7 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 3 show status like "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -69,7 +69,7 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 6 show status like "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -93,14 +93,14 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 2 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 +Qcache_hits 1 commit; show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 2 drop table t3,t2,t1; CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) PARTITION BY HASH (id) PARTITIONS 3; select count(*) from t1; @@ -164,7 +164,7 @@ count(*) 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 connection connection1 SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w'; count(*) @@ -197,9 +197,9 @@ count(*) 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 +Qcache_hits 1 set @@global.query_cache_size = @save_query_cache_size; drop table t2; diff --git a/mysql-test/r/partition_cache_innodb.result b/mysql-test/r/partition_cache_innodb.result new file mode 100644 index 00000000000..0d0abbb096c --- /dev/null +++ b/mysql-test/r/partition_cache_innodb.result @@ -0,0 +1,151 @@ +SET SESSION STORAGE_ENGINE = innodb; +drop table if exists t1; +set @save_query_cache_size = @@global.query_cache_size; +# Test that partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = InnoDB, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = InnoDB, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# Test that sub-partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +) +PARTITION BY RANGE (TO_DAYS(created_at)) +subpartition by hash(cool) subpartitions 3 ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +SUBPARTITION BY HASH (cool) +SUBPARTITIONS 3 +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = InnoDB, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = InnoDB, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# +# MySQL bug#53775 Query on partitioned table returns cached result +# from previous transaction +# +flush query cache; +flush status; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +INSERT INTO t1 VALUES (1, now(), 0); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +BEGIN; +UPDATE `t1` SET `cool` = 1 WHERE `id` = 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +BEGIN; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +drop table t1; +set @@global.query_cache_size = @save_query_cache_size; diff --git a/mysql-test/r/partition_cache_myisam.result b/mysql-test/r/partition_cache_myisam.result new file mode 100644 index 00000000000..0b617c03590 --- /dev/null +++ b/mysql-test/r/partition_cache_myisam.result @@ -0,0 +1,153 @@ +SET SESSION STORAGE_ENGINE = myisam; +drop table if exists t1; +set @save_query_cache_size = @@global.query_cache_size; +# Test that partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = MyISAM, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = MyISAM, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# Test that sub-partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +) +PARTITION BY RANGE (TO_DAYS(created_at)) +subpartition by hash(cool) subpartitions 3 ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +SUBPARTITION BY HASH (cool) +SUBPARTITIONS 3 +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = MyISAM, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = MyISAM, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# +# MySQL bug#53775 Query on partitioned table returns cached result +# from previous transaction +# +flush query cache; +flush status; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +INSERT INTO t1 VALUES (1, now(), 0); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +BEGIN; +UPDATE `t1` SET `cool` = 1 WHERE `id` = 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +BEGIN; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +set @@global.query_cache_size = @save_query_cache_size; diff --git a/mysql-test/t/partition_cache_innodb.test b/mysql-test/t/partition_cache_innodb.test new file mode 100644 index 00000000000..dbcfea3088c --- /dev/null +++ b/mysql-test/t/partition_cache_innodb.test @@ -0,0 +1,14 @@ +# t/cache_innodb.test +# +# Last update: +# 2006-07-26 ML test refactored (MySQL 5.1) +# main code t/innodb_cache.test --> include/query_cache.inc +# new wrapper t/cache_innodb.test +# + +--source include/have_query_cache.inc +--source include/have_innodb.inc +--source include/have_partition.inc +let $engine_type= innodb; + +--source include/query_cache_partitions.inc diff --git a/mysql-test/t/partition_cache_myisam.test b/mysql-test/t/partition_cache_myisam.test new file mode 100644 index 00000000000..5347225f6da --- /dev/null +++ b/mysql-test/t/partition_cache_myisam.test @@ -0,0 +1,14 @@ +# t/cache_innodb.test +# +# Last update: +# 2006-07-26 ML test refactored (MySQL 5.1) +# main code t/innodb_cache.test --> include/query_cache.inc +# new wrapper t/cache_innodb.test +# + +--source include/have_query_cache.inc + +--source include/have_partition.inc +let $engine_type= myisam; + +--source include/query_cache_partitions.inc 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); diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index e6bece5b7ff..47a3abb78d2 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1652,6 +1652,47 @@ ha_rows ha_myisammrg::records() return myrg_records(file); } +uint ha_myisammrg::count_query_cache_dependant_tables(uint8 *tables_type) +{ + MYRG_INFO *file = myrg_info(); + /* + Here should be following statement + (*tables_type)|= HA_CACHE_TBL_NONTRANSACT; + but it has no effect because HA_CACHE_TBL_NONTRANSACT is 0 + */ + return (file->end_table - file->open_tables); +} + + +my_bool ha_myisammrg::register_query_cache_dependant_tables(THD *thd + __attribute__((unused)), + Query_cache *cache, + Query_cache_block_table **block_table, + uint *n) +{ + MYRG_INFO *file =myrg_info(); + DBUG_ENTER("ha_myisammrg::register_query_cache_dependant_tables"); + + for (MYRG_TABLE *table =file->open_tables; + table != file->end_table ; + table++) + { + char key[MAX_DBKEY_LENGTH]; + uint32 db_length; + uint key_length= cache->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 (!cache->insert_table(key_length, key, (*block_table), + db_length, + table_cache_type(), + 0, 0, TRUE)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} extern int myrg_panic(enum ha_panic_function flag); int myisammrg_panic(handlerton *hton, ha_panic_function flag) diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index e0dc6e07542..f5ba2ffef38 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -149,4 +149,10 @@ public: bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes); int check(THD* thd, HA_CHECK_OPT* check_opt); ha_rows records(); + 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); }; |