Commit 9f6a1c58 authored by unknown's avatar unknown

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.
parent 718bbcbf
# 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;
......@@ -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;
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;
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;
# 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
# 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
......@@ -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
......
......@@ -544,22 +544,20 @@ class ha_partition :public handler
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);
......
......@@ -1689,6 +1689,8 @@ class handler_add_index : public Sql_alloc
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 @@ class handler :public Sql_alloc
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
......
......@@ -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);
......
......@@ -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 @@ class Query_cache
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 @@ class Query_cache
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 @@ class Query_cache
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 @@ class Query_cache
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);
......
......@@ -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)
......
......@@ -149,4 +149,10 @@ class ha_myisammrg: public handler
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);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment