mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
More query cache optimizations
- Added query_cache_type == ALWAYS_OFF to turn of query cache permanently for new open tables. Without this option storage engines has to call query cache for all update querys and invalidate used tables that has a small overhead. When running benchmarks without query cache, this is the option to use! - Updated MyISAM, Aria, MYISAM_MRG and InnoDB to support ALWAYS_OFF. - Setting query_cache_size in a config file will not automatically enable the query cache. - Added query_cache_available() that functions can check if query cache can be used or if it is permanently disabled. - Moved things around in Query_cache::store_query() to get more work done outside of query cache mutex. - Same for Query_cache::send_result_to_client() Co-author: Thirunarayanan Balathandayuthapani <thiru@mariadb.com> - ÌnnoDB changes reviewed and improved
This commit is contained in:
@@ -1229,7 +1229,8 @@ The following specify which files/extra groups are read (specified before remain
|
||||
SQL_CACHE' at start of query (to avoid locks that ON and
|
||||
DEMAND have to take). TABLES = Cache only queries marked
|
||||
with SQL_CACHE or queries where all tables are created
|
||||
with SQL_CACHE=1
|
||||
with SQL_CACHE=1. ALWAYS_OFF = query cache is permanently
|
||||
OFF and cannot be enabled
|
||||
--query-cache-wlock-invalidate
|
||||
Invalidate queries in query cache on LOCK for write
|
||||
--query-prealloc-size=#
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
--query-cache-size=1355776
|
||||
--query-cache-type=ON
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
select @@query_cache_type;
|
||||
@@query_cache_type
|
||||
ON
|
||||
set @sql_mode_save=@@global.sql_mode;
|
||||
set @query_cache_type_save=@@global.query_cache_type;
|
||||
set @query_cache_size_save=@@global.query_cache_size;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#
|
||||
# Tests with query cache
|
||||
#
|
||||
select @@query_cache_type;
|
||||
set @sql_mode_save=@@global.sql_mode;
|
||||
set @query_cache_type_save=@@global.query_cache_type;
|
||||
set @query_cache_size_save=@@global.query_cache_size;
|
||||
|
||||
@@ -99,8 +99,8 @@ SELECT @@global.query_cache_type;
|
||||
DEMAND
|
||||
SET @@global.query_cache_type = 0.4;
|
||||
ERROR 42000: Incorrect argument type to variable 'query_cache_type'
|
||||
SET @@global.query_cache_type = 5;
|
||||
ERROR 42000: Variable 'query_cache_type' can't be set to the value of '5'
|
||||
SET @@global.query_cache_type = 6;
|
||||
ERROR 42000: Variable 'query_cache_type' can't be set to the value of '6'
|
||||
'#---------------------FN_DYNVARS_134_08----------------------#'
|
||||
SET @@global.query_cache_type = TRUE;
|
||||
SELECT @@global.query_cache_type;
|
||||
@@ -120,11 +120,24 @@ SET global query_cache_type = 0;
|
||||
SELECT @@global.query_cache_type;
|
||||
@@global.query_cache_type
|
||||
OFF
|
||||
SET @@global.query_cache_type = @global_start_value;
|
||||
SET global query_cache_type = ON;
|
||||
SELECT @@global.query_cache_type;
|
||||
@@global.query_cache_type
|
||||
ON
|
||||
SET @@query_cache_type = ALWAYS_OFF;
|
||||
select @@query_cache_type;
|
||||
@@query_cache_type
|
||||
OFF
|
||||
SET @@session.query_cache_type = @session_start_value;
|
||||
SELECT @@session.query_cache_type;
|
||||
@@session.query_cache_type
|
||||
SET @@query_cache_type= ON;
|
||||
SET @@global.query_cache_type = ALWAYS_OFF;
|
||||
SELECT @@global.query_cache_type;
|
||||
@@global.query_cache_type
|
||||
ALWAYS_OFF
|
||||
select @@query_cache_type;
|
||||
@@query_cache_type
|
||||
OFF
|
||||
SET @@global.query_cache_type = ON;
|
||||
ERROR HY000: Query cache is globally disabled and you can't enable it only for this session
|
||||
SET @@session.query_cache_type = ON;
|
||||
ERROR HY000: Query cache is globally disabled and you can't enable it only for this session
|
||||
# restart
|
||||
|
||||
@@ -3375,11 +3375,11 @@ COMMAND_LINE_ARGUMENT OPTIONAL
|
||||
VARIABLE_NAME QUERY_CACHE_TYPE
|
||||
VARIABLE_SCOPE SESSION
|
||||
VARIABLE_TYPE ENUM
|
||||
VARIABLE_COMMENT OFF = Don't cache or retrieve results. ON = Cache all results except for queries marked with SQL_NO_CACHE. DEMAND = Cache only queries marked with SQL_CACHE. DEMAND_STRICT = Like DEMAND but only check for 'SELECT SQL_CACHE' at start of query (to avoid locks that ON and DEMAND have to take). TABLES = Cache only queries marked with SQL_CACHE or queries where all tables are created with SQL_CACHE=1
|
||||
VARIABLE_COMMENT OFF = Don't cache or retrieve results. ON = Cache all results except for queries marked with SQL_NO_CACHE. DEMAND = Cache only queries marked with SQL_CACHE. DEMAND_STRICT = Like DEMAND but only check for 'SELECT SQL_CACHE' at start of query (to avoid locks that ON and DEMAND have to take). TABLES = Cache only queries marked with SQL_CACHE or queries where all tables are created with SQL_CACHE=1. ALWAYS_OFF = query cache is permanently OFF and cannot be enabled
|
||||
NUMERIC_MIN_VALUE NULL
|
||||
NUMERIC_MAX_VALUE NULL
|
||||
NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST OFF,ON,DEMAND,DEMAND_STRICT,TABLES
|
||||
ENUM_VALUE_LIST OFF,ON,DEMAND,DEMAND_STRICT,TABLES,ALWAYS_OFF
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME QUERY_CACHE_WLOCK_INVALIDATE
|
||||
|
||||
@@ -3625,11 +3625,11 @@ COMMAND_LINE_ARGUMENT OPTIONAL
|
||||
VARIABLE_NAME QUERY_CACHE_TYPE
|
||||
VARIABLE_SCOPE SESSION
|
||||
VARIABLE_TYPE ENUM
|
||||
VARIABLE_COMMENT OFF = Don't cache or retrieve results. ON = Cache all results except for queries marked with SQL_NO_CACHE. DEMAND = Cache only queries marked with SQL_CACHE. DEMAND_STRICT = Like DEMAND but only check for 'SELECT SQL_CACHE' at start of query (to avoid locks that ON and DEMAND have to take). TABLES = Cache only queries marked with SQL_CACHE or queries where all tables are created with SQL_CACHE=1
|
||||
VARIABLE_COMMENT OFF = Don't cache or retrieve results. ON = Cache all results except for queries marked with SQL_NO_CACHE. DEMAND = Cache only queries marked with SQL_CACHE. DEMAND_STRICT = Like DEMAND but only check for 'SELECT SQL_CACHE' at start of query (to avoid locks that ON and DEMAND have to take). TABLES = Cache only queries marked with SQL_CACHE or queries where all tables are created with SQL_CACHE=1. ALWAYS_OFF = query cache is permanently OFF and cannot be enabled
|
||||
NUMERIC_MIN_VALUE NULL
|
||||
NUMERIC_MAX_VALUE NULL
|
||||
NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST OFF,ON,DEMAND,DEMAND_STRICT,TABLES
|
||||
ENUM_VALUE_LIST OFF,ON,DEMAND,DEMAND_STRICT,TABLES,ALWAYS_OFF
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME QUERY_CACHE_WLOCK_INVALIDATE
|
||||
|
||||
@@ -161,7 +161,7 @@ SELECT @@global.query_cache_type;
|
||||
SET @@global.query_cache_type = 0.4;
|
||||
|
||||
--Error ER_WRONG_VALUE_FOR_VAR
|
||||
SET @@global.query_cache_type = 5;
|
||||
SET @@global.query_cache_type = 6;
|
||||
|
||||
|
||||
--echo '#---------------------FN_DYNVARS_134_08----------------------#'
|
||||
@@ -187,15 +187,27 @@ SELECT @@query_cache_type;
|
||||
SET global query_cache_type = 0;
|
||||
SELECT @@global.query_cache_type;
|
||||
|
||||
##############################
|
||||
# Restore initial value #
|
||||
##############################
|
||||
################################
|
||||
# Change value permanently #
|
||||
################################
|
||||
|
||||
SET @@global.query_cache_type = @global_start_value;
|
||||
SET global query_cache_type = ON;
|
||||
SELECT @@global.query_cache_type;
|
||||
|
||||
SET @@session.query_cache_type = @session_start_value;
|
||||
SELECT @@session.query_cache_type;
|
||||
SET @@query_cache_type = ALWAYS_OFF;
|
||||
select @@query_cache_type;
|
||||
SET @@query_cache_type= ON;
|
||||
|
||||
SET @@global.query_cache_type = ALWAYS_OFF;
|
||||
SELECT @@global.query_cache_type;
|
||||
select @@query_cache_type;
|
||||
|
||||
--error ER_QUERY_CACHE_IS_GLOBALY_DISABLED
|
||||
SET @@global.query_cache_type = ON;
|
||||
--error ER_QUERY_CACHE_IS_GLOBALY_DISABLED
|
||||
SET @@session.query_cache_type = ON;
|
||||
|
||||
--source include/restart_mysqld.inc
|
||||
|
||||
########################################################################
|
||||
# END OF query_cache_type TESTS #
|
||||
|
||||
@@ -5148,12 +5148,6 @@ static int init_server_components()
|
||||
query_cache_set_min_res_unit(query_cache_min_res_unit);
|
||||
query_cache_result_size_limit(query_cache_limit);
|
||||
/* if we set size of QC non zero in config then probably we want it ON */
|
||||
if (query_cache_size != 0 &&
|
||||
global_system_variables.query_cache_type == QUERY_CACHE_TYPE_OFF &&
|
||||
!IS_SYSVAR_AUTOSIZE(&query_cache_size))
|
||||
{
|
||||
global_system_variables.query_cache_type= QUERY_CACHE_TYPE_ON;
|
||||
}
|
||||
query_cache_init();
|
||||
DBUG_ASSERT(query_cache_size < ULONG_MAX);
|
||||
query_cache_resize((ulong)query_cache_size);
|
||||
|
||||
138
sql/sql_cache.cc
138
sql/sql_cache.cc
@@ -571,9 +571,10 @@ insert_space:
|
||||
@param thd thread handle
|
||||
*/
|
||||
|
||||
void inline fix_local_query_cache_mode(THD *thd)
|
||||
void fix_local_query_cache_mode(THD *thd)
|
||||
{
|
||||
if (global_system_variables.query_cache_type == QUERY_CACHE_TYPE_OFF)
|
||||
if (global_system_variables.query_cache_type == QUERY_CACHE_TYPE_OFF ||
|
||||
global_system_variables.query_cache_type == QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
thd->variables.query_cache_type= QUERY_CACHE_TYPE_OFF;
|
||||
}
|
||||
|
||||
@@ -1285,6 +1286,16 @@ void mysql_query_cache_invalidate4(THD *thd,
|
||||
query_cache.invalidate(thd, key, (uint32) key_length, (my_bool) using_trx);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
/* Return 1 if query cache is on or could be enabled later */
|
||||
my_bool query_cache_available()
|
||||
{
|
||||
return (global_system_variables.query_cache_type !=
|
||||
QUERY_CACHE_TYPE_ALWAYS_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Query_cache methods
|
||||
@@ -1361,13 +1372,14 @@ size_t Query_cache::resize(size_t query_cache_size_arg)
|
||||
will not be reflected on global_system_variables.query_cache_type
|
||||
*/
|
||||
if (new_query_cache_size &&
|
||||
global_system_variables.query_cache_type != QUERY_CACHE_TYPE_OFF)
|
||||
global_system_variables.query_cache_type != QUERY_CACHE_TYPE_OFF &&
|
||||
global_system_variables.query_cache_type != QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
{
|
||||
DBUG_EXECUTE("check_querycache",check_integrity(1););
|
||||
m_cache_status= OK; // size > 0 => enable cache
|
||||
m_cache_status= OK; // size > 0 => resize cache
|
||||
}
|
||||
else
|
||||
m_cache_status= DISABLED; // size 0 means the cache disabled
|
||||
m_cache_status= DISABLED; // size 0 means the cache disabled
|
||||
|
||||
unlock();
|
||||
DBUG_RETURN(new_query_cache_size);
|
||||
@@ -1424,7 +1436,6 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
|
||||
}
|
||||
#endif //EMBEDDED_LIBRARY
|
||||
|
||||
|
||||
/* The following assert fails if we haven't called send_result_to_client */
|
||||
DBUG_ASSERT(thd->base_query.is_alloced() ||
|
||||
thd->base_query.ptr() == thd->query());
|
||||
@@ -1498,33 +1509,6 @@ def_week_frmt: %zu, in_trans: %d, autocommit: %d",
|
||||
(int)flags.in_trans,
|
||||
(int)flags.autocommit));
|
||||
|
||||
/*
|
||||
A table- or a full flush operation can potentially take a long time to
|
||||
finish. We choose not to wait for them and skip caching statements
|
||||
instead.
|
||||
|
||||
In case the wait time can't be determined there is an upper limit which
|
||||
causes try_lock() to abort with a time out.
|
||||
|
||||
The 'TIMEOUT' parameter indicate that the lock is allowed to timeout
|
||||
|
||||
*/
|
||||
if (try_lock(thd, Query_cache::TIMEOUT))
|
||||
DBUG_VOID_RETURN;
|
||||
if (query_cache_size == 0)
|
||||
{
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
DUMP(this);
|
||||
|
||||
if (ask_handler_allowance(thd, tables_used))
|
||||
{
|
||||
refused++;
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
query= thd->base_query.ptr();
|
||||
query_length= thd->base_query.length();
|
||||
|
||||
@@ -1549,6 +1533,34 @@ def_week_frmt: %zu, in_trans: %d, autocommit: %d",
|
||||
memcpy((void*) (query + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
|
||||
&flags, QUERY_CACHE_FLAGS_SIZE);
|
||||
|
||||
/*
|
||||
A table- or a full flush operation can potentially take a long time to
|
||||
finish. We choose not to wait for them and skip caching statements
|
||||
instead.
|
||||
|
||||
In case the wait time can't be determined there is an upper limit which
|
||||
causes try_lock() to abort with a time out.
|
||||
|
||||
The 'TIMEOUT' parameter indicate that the lock is allowed to timeout
|
||||
|
||||
*/
|
||||
if (try_lock(thd, Query_cache::TIMEOUT))
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
if (query_cache_size == 0) // Recheck under lock
|
||||
{
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
DUMP(this);
|
||||
|
||||
if (ask_handler_allowance(thd, tables_used))
|
||||
{
|
||||
refused++;
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* Check if another thread is processing the same query? */
|
||||
Query_cache_block *competitor = (Query_cache_block *)
|
||||
my_hash_search(&queries, (uchar*) query, tot_length);
|
||||
@@ -1913,21 +1925,6 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Try to obtain an exclusive lock on the query cache. If the cache is
|
||||
disabled or if a full cache flush is in progress, the attempt to
|
||||
get the lock is aborted.
|
||||
|
||||
The TIMEOUT parameter indicate that the lock is allowed to timeout.
|
||||
*/
|
||||
if (try_lock(thd, Query_cache::TIMEOUT))
|
||||
goto err;
|
||||
|
||||
if (query_cache_size == 0)
|
||||
{
|
||||
thd->query_cache_is_applicable= 0; // Query can't be cached
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
Query_cache_block *query_block;
|
||||
if (thd->variables.query_cache_strip_comments)
|
||||
@@ -1961,8 +1958,6 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
|
||||
DBUG_PRINT("qcache", ("No active database"));
|
||||
}
|
||||
|
||||
THD_STAGE_INFO(thd, stage_checking_query_cache_for_query);
|
||||
|
||||
// fill all gaps between fields with 0 to get repeatable key
|
||||
bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
|
||||
flags.client_long_flag= MY_TEST(thd->client_capabilities & CLIENT_LONG_FLAG);
|
||||
@@ -2019,6 +2014,24 @@ def_week_frmt: %zu, in_trans: %d, autocommit: %d",
|
||||
memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
|
||||
(uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
|
||||
|
||||
/*
|
||||
Try to obtain an exclusive lock on the query cache. If the cache is
|
||||
disabled or if a full cache flush is in progress, the attempt to
|
||||
get the lock is aborted.
|
||||
|
||||
The TIMEOUT parameter indicate that the lock is allowed to timeout.
|
||||
*/
|
||||
if (try_lock(thd, Query_cache::TIMEOUT))
|
||||
goto err;
|
||||
|
||||
if (query_cache_size == 0)
|
||||
{
|
||||
thd->query_cache_is_applicable= 0; // Query can't be cached
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
THD_STAGE_INFO(thd, stage_checking_query_cache_for_query);
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
bool once_more;
|
||||
once_more= true;
|
||||
@@ -2617,7 +2630,8 @@ void Query_cache::init()
|
||||
time. This is because we want to avoid locking the QC specific
|
||||
mutex if query cache isn't going to be used.
|
||||
*/
|
||||
if (global_system_variables.query_cache_type == QUERY_CACHE_TYPE_OFF)
|
||||
if (global_system_variables.query_cache_type == QUERY_CACHE_TYPE_OFF ||
|
||||
global_system_variables.query_cache_type == QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
{
|
||||
m_cache_status= DISABLE_REQUEST;
|
||||
free_cache();
|
||||
@@ -4093,8 +4107,8 @@ void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
|
||||
are defined with SQL_CACHE=1
|
||||
|
||||
RETURN
|
||||
0 error
|
||||
>0 number of tables
|
||||
0 error.
|
||||
>0 number of tables ; *tables_type is up to date
|
||||
|
||||
Notes:
|
||||
MERGE TABLE childs are not tested for SQL_CACHE=1.
|
||||
@@ -4139,8 +4153,7 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
|
||||
{
|
||||
DBUG_PRINT("qcache", ("Don't cache statement as it refers to "
|
||||
"tables with column privileges."));
|
||||
thd->query_cache_is_applicable= 0; // Query can't be cached
|
||||
thd->lex->safe_to_cache_query= 0; // For prepared statements
|
||||
goto not_cacheable;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif
|
||||
@@ -4167,27 +4180,34 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
|
||||
table->s->table_name.str,
|
||||
table->s->db.str,
|
||||
table->s->db_type()->db_type));
|
||||
if (table->s->table_category != TABLE_CATEGORY_USER ||
|
||||
table->s->query_cache == HA_CHOICE_NO)
|
||||
goto not_cacheable;
|
||||
|
||||
cache_type= table->file->table_cache_type();
|
||||
*tables_type|= cache_type;
|
||||
|
||||
table_count+= table->file->count_query_cache_dependant_tables(tables_type);
|
||||
|
||||
if ((no_cache= ((cache_type & HA_CACHE_TBL_NOCACHE) ||
|
||||
table->s->table_category != TABLE_CATEGORY_USER ||
|
||||
table->s->query_cache == HA_CHOICE_NO)) ||
|
||||
if ((no_cache= (cache_type & HA_CACHE_TBL_NOCACHE)) ||
|
||||
(only_sqlcache_tables && table->s->query_cache != HA_CHOICE_YES))
|
||||
{
|
||||
DBUG_PRINT("qcache",
|
||||
("select not cacheable: temporary, system or "
|
||||
"other non-cacheable table(s)"));
|
||||
thd->query_cache_is_applicable= 0; // Query can't be cached
|
||||
/* For prepared statements */
|
||||
if (no_cache)
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
thd->query_cache_is_applicable= 0; // Query can't be cached
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(table_count);
|
||||
|
||||
not_cacheable:
|
||||
thd->lex->safe_to_cache_query= 0; // For prepared statements
|
||||
thd->query_cache_is_applicable= 0; // Query can't be cached
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ typedef struct st_changed_table_list CHANGED_TABLE_LIST;
|
||||
#define QUERY_CACHE_TYPE_DEMAND 2
|
||||
#define QUERY_CACHE_TYPE_DEMAND_STRICT 3
|
||||
#define QUERY_CACHE_TYPE_TABLES 4
|
||||
#define QUERY_CACHE_TYPE_ALWAYS_OFF 5
|
||||
|
||||
/* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */
|
||||
#define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4
|
||||
@@ -265,6 +266,7 @@ extern "C"
|
||||
my_bool);
|
||||
const uchar *query_cache_table_get_key(const void *record, size_t *length,
|
||||
my_bool);
|
||||
my_bool query_cache_available();
|
||||
}
|
||||
extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
|
||||
|
||||
@@ -580,7 +582,6 @@ struct Query_cache_query_flags
|
||||
};
|
||||
#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
|
||||
#define QUERY_CACHE_DB_LENGTH_SIZE 2
|
||||
#include "sql_cache.h"
|
||||
#define query_cache_abort(A,B) query_cache.abort(A,B)
|
||||
#define query_cache_end_of_result(A) query_cache.end_of_result(A)
|
||||
#define query_cache_store_query(A, B) query_cache.store_query(A, B)
|
||||
@@ -601,6 +602,8 @@ struct Query_cache_query_flags
|
||||
#define query_cache_is_cacheable_query(L) \
|
||||
(((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query)
|
||||
|
||||
extern void fix_local_query_cache_mode(THD *thd);
|
||||
|
||||
/* See also sql_class.h for some inline query cache functions */
|
||||
|
||||
extern MYSQL_PLUGIN_IMPORT Query_cache query_cache;
|
||||
|
||||
@@ -1442,6 +1442,7 @@ void THD::init()
|
||||
backup_commit_lock= 0;
|
||||
num_of_strings_sorted_on_truncated_length= 0;
|
||||
query_cache_is_applicable= 0;
|
||||
fix_local_query_cache_mode(this);
|
||||
#ifdef WITH_WSREP
|
||||
wsrep_last_query_id= 0;
|
||||
wsrep_xid.null();
|
||||
|
||||
@@ -3542,27 +3542,43 @@ static Sys_var_ulong Sys_query_cache_min_res_unit(
|
||||
ON_UPDATE(fix_qcache_min_res_unit));
|
||||
|
||||
static const char *query_cache_type_names[]=
|
||||
{ "OFF", "ON", "DEMAND", "DEMAND_STRICT", "TABLES", 0};
|
||||
{ "OFF", "ON", "DEMAND", "DEMAND_STRICT", "TABLES", "ALWAYS_OFF", NullS};
|
||||
|
||||
static bool check_query_cache_type(sys_var *self, THD *thd, set_var *var)
|
||||
{
|
||||
int global_query_cache_type= global_system_variables.query_cache_type;
|
||||
|
||||
if (query_cache.is_disable_in_progress())
|
||||
{
|
||||
my_error(ER_QUERY_CACHE_IS_DISABLED, MYF(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (var->type != OPT_GLOBAL &&
|
||||
global_system_variables.query_cache_type == QUERY_CACHE_TYPE_OFF)
|
||||
if (global_query_cache_type == QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
{
|
||||
if (var->value)
|
||||
my_error(ER_QUERY_CACHE_IS_GLOBALY_DISABLED, MYF(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (var->type != OPT_GLOBAL)
|
||||
{
|
||||
if (global_query_cache_type == QUERY_CACHE_TYPE_OFF ||
|
||||
global_query_cache_type == QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
{
|
||||
if (var->save_result.ulonglong_value != 0)
|
||||
if (var->value)
|
||||
{
|
||||
my_error(ER_QUERY_CACHE_IS_GLOBALY_DISABLED, MYF(0));
|
||||
return true;
|
||||
if (var->save_result.ulonglong_value != 0)
|
||||
{
|
||||
my_error(ER_QUERY_CACHE_IS_GLOBALY_DISABLED, MYF(0));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (var->value &&
|
||||
var->save_result.ulonglong_value == QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
{
|
||||
/* session should never be QUERY_CACHE_TYPE_ALWAYS_OFF */
|
||||
var->save_result.ulonglong_value= QUERY_CACHE_TYPE_OFF;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -3573,7 +3589,8 @@ static bool fix_query_cache_type(sys_var *self, THD *thd, enum_var_type type)
|
||||
if (type != OPT_GLOBAL)
|
||||
return false;
|
||||
|
||||
if (global_system_variables.query_cache_type != QUERY_CACHE_TYPE_OFF)
|
||||
if (global_system_variables.query_cache_type != QUERY_CACHE_TYPE_OFF &&
|
||||
global_system_variables.query_cache_type != QUERY_CACHE_TYPE_ALWAYS_OFF)
|
||||
{
|
||||
if (query_cache.is_disabled())
|
||||
{
|
||||
@@ -3596,7 +3613,8 @@ static Sys_var_enum Sys_query_cache_type(
|
||||
"DEMAND_STRICT = Like DEMAND but only check for 'SELECT SQL_CACHE' "
|
||||
"at start of query (to avoid locks that ON and DEMAND have to take). "
|
||||
"TABLES = Cache only queries marked with SQL_CACHE or queries where all "
|
||||
"tables are created with SQL_CACHE=1",
|
||||
"tables are created with SQL_CACHE=1. "
|
||||
"ALWAYS_OFF = query cache is permanently OFF and cannot be enabled",
|
||||
NO_SET_STMT SESSION_VAR(query_cache_type), CMD_LINE(REQUIRED_ARG),
|
||||
query_cache_type_names, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
|
||||
ON_CHECK(check_query_cache_type),
|
||||
|
||||
@@ -150,6 +150,7 @@ dict_table_t *dict_table_t::create(const span<const char> &name,
|
||||
table->name.m_name= mem_strdupl(name.data(), name.size());
|
||||
table->mdl_name.m_name= table->name.m_name;
|
||||
table->is_system_db= dict_mem_table_is_system(table->name.m_name);
|
||||
table->query_cache= query_cache_available();
|
||||
table->space= space;
|
||||
table->space_id= space ? space->id : UINT32_MAX;
|
||||
table->n_t_cols= static_cast<unsigned>(n_cols + DATA_N_SYS_COLS) &
|
||||
|
||||
@@ -3047,6 +3047,25 @@ static void innodb_ahi_enable(dict_table_t *innodb_table,
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Copy the query cache usage flag from MariaDB table definition.
|
||||
Query is never cached if it uses that is not plain user table
|
||||
(temporary table) or that was created with SQL_CACHE=0
|
||||
@param innodb_table InnoDB table
|
||||
@param table MariaDB table definition */
|
||||
static void innobase_copy_query_cache_flag(dict_table_t *innodb_table,
|
||||
const TABLE *table) noexcept
|
||||
{
|
||||
const bool query_cache= table->s->query_cache != HA_CHOICE_NO &&
|
||||
!innodb_table->is_temporary() && query_cache_available();
|
||||
|
||||
if (query_cache && !innodb_table->query_cache)
|
||||
{
|
||||
innodb_table->query_cache_inv_trx_id= trx_sys.get_max_trx_id();
|
||||
innodb_table->query_cache= query_cache;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************//**
|
||||
Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object.
|
||||
Those flags are stored in .frm file and end up in the MySQL table object,
|
||||
@@ -3068,6 +3087,7 @@ innobase_copy_frm_flags_from_create_info(
|
||||
innodb_ahi_enable(innodb_table, create_info->option_struct, table);
|
||||
#endif
|
||||
}
|
||||
innobase_copy_query_cache_flag(innodb_table, table);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3090,6 +3110,7 @@ void innobase_copy_frm_flags_from_table(dict_table_t *innodb_table,
|
||||
innodb_ahi_enable(innodb_table, table_share->option_struct_table, table);
|
||||
#endif
|
||||
}
|
||||
innobase_copy_query_cache_flag(innodb_table, table);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
||||
@@ -2521,6 +2521,7 @@ public:
|
||||
/*!< True if the table belongs to a system
|
||||
database (mysql, information_schema or
|
||||
performance_schema) */
|
||||
bool query_cache; /* 1 if query cache is in use */
|
||||
dict_frm_t dict_frm_mismatch;
|
||||
/*!< !DICT_FRM_CONSISTENT==0 if data
|
||||
dictionary information and
|
||||
@@ -2695,7 +2696,8 @@ public:
|
||||
/** Timestamp of the last modification of this table. */
|
||||
Atomic_relaxed<time_t> update_time;
|
||||
/** Transactions whose view low limit is greater than this number are
|
||||
not allowed to access the MariaDB query cache.
|
||||
not allowed to access the MariaDB query cache. Maintained while
|
||||
query_cache is set
|
||||
@see innobase_query_caching_table_check_low()
|
||||
@see trx_t::commit_tables() */
|
||||
Atomic_relaxed<trx_id_t> query_cache_inv_trx_id;
|
||||
|
||||
@@ -1022,7 +1022,8 @@ row_ins_foreign_check_on_constraint(
|
||||
the mutex rank above the lock_sys.latch. The query cache mutex
|
||||
has a rank just above the lock_sys.latch. */
|
||||
|
||||
row_ins_invalidate_query_cache(thr, table->name.m_name);
|
||||
if (table->query_cache)
|
||||
row_ins_invalidate_query_cache(thr, table->name.m_name);
|
||||
|
||||
node = static_cast<upd_node_t*>(thr->run_node);
|
||||
|
||||
|
||||
@@ -1313,13 +1313,15 @@ inline void trx_t::commit_tables()
|
||||
{
|
||||
if (undo_no && !mod_tables.empty())
|
||||
{
|
||||
const trx_id_t max_trx_id= trx_sys.get_max_trx_id();
|
||||
trx_id_t max_trx_id= 0;
|
||||
const auto now= start_time;
|
||||
|
||||
for (const auto &p : mod_tables)
|
||||
{
|
||||
dict_table_t *table= p.first;
|
||||
table->update_time= now;
|
||||
if (!table->query_cache) continue;
|
||||
if (!max_trx_id) max_trx_id= trx_sys.get_max_trx_id();
|
||||
table->query_cache_inv_trx_id= max_trx_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1151,8 +1151,8 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked)
|
||||
}
|
||||
if (aria_readonly)
|
||||
file->s->options|= HA_OPTION_READ_ONLY_DATA;
|
||||
|
||||
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
|
||||
if (table->s->query_cache != HA_CHOICE_NO && query_cache_available())
|
||||
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
|
||||
/* Set external_ref, mainly for temporary tables */
|
||||
file->external_ref= (void*) table; // For ma_killed()
|
||||
|
||||
@@ -3108,10 +3108,10 @@ static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
|
||||
If table has changed by this statement, invalidate it from the query
|
||||
cache
|
||||
*/
|
||||
if (table->row_changes != table->start_row_changes)
|
||||
if (table->s->chst_invalidator &&
|
||||
table->row_changes != table->start_row_changes)
|
||||
{
|
||||
table->start_row_changes= table->row_changes;
|
||||
DBUG_ASSERT(table->s->chst_invalidator != NULL);
|
||||
(*table->s->chst_invalidator)(table->s->data_file_name.str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,11 +334,12 @@ void _ma_update_status(void* param)
|
||||
DBUG_ASSERT(!info->s->base.born_transactional);
|
||||
share->state.state= *info->state;
|
||||
info->state= &share->state.state;
|
||||
DBUG_PRINT("info", ("invalidator... '%s' (status update)",
|
||||
info->s->data_file_name.str));
|
||||
DBUG_ASSERT(info->s->chst_invalidator != NULL);
|
||||
(*info->s->chst_invalidator)((const char *)info->s->data_file_name.str);
|
||||
|
||||
if (info->s->chst_invalidator)
|
||||
{
|
||||
DBUG_PRINT("info", ("invalidator... '%s' (status update)",
|
||||
info->s->data_file_name.str));
|
||||
(*info->s->chst_invalidator)((const char *)info->s->data_file_name.str);
|
||||
}
|
||||
}
|
||||
info->append_insert_at_end= 0;
|
||||
}
|
||||
|
||||
@@ -813,7 +813,8 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
|
||||
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
|
||||
return (my_errno ? my_errno : -1);
|
||||
|
||||
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
|
||||
if (table->s->query_cache != HA_CHOICE_NO && query_cache_available())
|
||||
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
|
||||
/* Set external_ref, mainly for temporary tables */
|
||||
file->external_ref= (void*) table; // For mi_killed()
|
||||
|
||||
|
||||
@@ -335,8 +335,8 @@ void mi_update_status(void* param)
|
||||
info->s->state.state= *info->state;
|
||||
DBUG_PRINT("info", ("invalidator... '%s' (status update)",
|
||||
info->filename));
|
||||
DBUG_ASSERT(info->s->chst_invalidator != NULL);
|
||||
(*info->s->chst_invalidator)((const char *)info->filename);
|
||||
if (info->s->chst_invalidator)
|
||||
(*info->s->chst_invalidator)((const char *)info->filename);
|
||||
}
|
||||
|
||||
info->state= &info->s->state.state;
|
||||
|
||||
@@ -832,7 +832,8 @@ int ha_myisammrg::attach_children(void)
|
||||
goto err;
|
||||
}
|
||||
DBUG_PRINT("myrg", ("calling myrg_extrafunc"));
|
||||
myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
|
||||
if (query_cache_available())
|
||||
myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
|
||||
if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
|
||||
test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
|
||||
myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK,0);
|
||||
|
||||
Reference in New Issue
Block a user