summaryrefslogtreecommitdiff
path: root/sql/sql_cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_cache.cc')
-rw-r--r--sql/sql_cache.cc241
1 files changed, 151 insertions, 90 deletions
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 5ba32e0bbd7..8f6187f9ce4 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -328,7 +328,7 @@ TODO list:
(This could be done with almost no speed penalty)
*/
-#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
#include "sql_cache.h"
#include "sql_parse.h" // check_table_access
@@ -336,6 +336,7 @@ TODO list:
#include "sql_acl.h" // SELECT_ACL
#include "sql_base.h" // TMP_TABLE_KEY_EXTRA
#include "debug_sync.h" // DEBUG_SYNC
+#include "sql_table.h"
#ifdef HAVE_QUERY_CACHE
#include <m_ctype.h>
#include <my_dir.h>
@@ -345,6 +346,7 @@ TODO list:
#include "probes_mysql.h"
#include "log_slow.h"
#include "transaction.h"
+#include "strfunc.h"
const uchar *query_state_map;
@@ -412,23 +414,28 @@ const uchar *query_state_map;
struct Query_cache_wait_state
{
THD *m_thd;
- const char *m_proc_info;
+ PSI_stage_info m_old_stage;
+ const char *m_func;
+ const char *m_file;
+ int m_line;
Query_cache_wait_state(THD *thd, const char *func,
const char *file, unsigned int line)
: m_thd(thd),
- m_proc_info(NULL)
+ m_old_stage(),
+ m_func(func), m_file(file), m_line(line)
{
if (m_thd)
- m_proc_info= set_thd_proc_info(m_thd,
- "Waiting for query cache lock",
- func, file, line);
+ set_thd_stage_info(m_thd,
+ &stage_waiting_for_query_cache_lock,
+ &m_old_stage,
+ m_func, m_file, m_line);
}
~Query_cache_wait_state()
{
if (m_thd)
- set_thd_proc_info(m_thd, m_proc_info, NULL, NULL, 0);
+ set_thd_stage_info(m_thd, &m_old_stage, NULL, m_func, m_file, m_line);
}
};
@@ -1038,8 +1045,8 @@ void query_cache_insert(const char *packet, ulong length,
/*
Current_thd can be NULL when a new connection is immediately ended
due to "Too many connections". thd->store_globals() has not been
- called at this time and hence my_pthread_setspecific_ptr(THR_THD,
- this) has not been called for this thread.
+ called at this time and hence set_current_thd(this) has not been
+ called for this thread.
*/
if (!thd)
@@ -1143,7 +1150,7 @@ Query_cache::abort(Query_cache_tls *query_cache_tls)
if (query_block)
{
thd= current_thd;
- thd_proc_info(thd, "storing result in query cache");
+ THD_STAGE_INFO(thd, stage_storing_result_in_query_cache);
DUMP(this);
BLOCK_LOCK_WR(query_block);
// The following call will remove the lock on query_block
@@ -1170,7 +1177,7 @@ void Query_cache::end_of_result(THD *thd)
DBUG_VOID_RETURN;
/* Ensure that only complete results are cached. */
- DBUG_ASSERT(thd->stmt_da->is_eof());
+ DBUG_ASSERT(thd->get_stmt_da()->is_eof());
if (thd->killed)
{
@@ -1198,7 +1205,7 @@ void Query_cache::end_of_result(THD *thd)
suitable size if needed and setting block type. Since this is the last
block, the writer should be dropped.
*/
- thd_proc_info(thd, "storing result in query cache");
+ THD_STAGE_INFO(thd, stage_storing_result_in_query_cache);
DUMP(this);
BLOCK_LOCK_WR(query_block);
Query_cache_query *header= query_block->query();
@@ -1222,7 +1229,7 @@ void Query_cache::end_of_result(THD *thd)
}
last_result_block= header->result()->prev;
allign_size= ALIGN_SIZE(last_result_block->used);
- len= max(query_cache.min_allocation_unit, allign_size);
+ len= MY_MAX(query_cache.min_allocation_unit, allign_size);
if (last_result_block->length >= query_cache.min_allocation_unit + len)
query_cache.split_block(last_result_block,len);
@@ -1402,9 +1409,9 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
Query_cache_query_flags flags;
// fill all gaps between fields with 0 to get repeatable key
bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
- flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
- flags.client_protocol_41= test(thd->client_capabilities &
- CLIENT_PROTOCOL_41);
+ flags.client_long_flag= MY_TEST(thd->client_capabilities & CLIENT_LONG_FLAG);
+ flags.client_protocol_41= MY_TEST(thd->client_capabilities &
+ CLIENT_PROTOCOL_41);
/*
Protocol influences result format, so statement results in the binary
protocol (COM_EXECUTE) cannot be served to statements asking for results
@@ -1413,10 +1420,10 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
flags.protocol_type= (unsigned int) thd->protocol->type();
/* PROTOCOL_LOCAL results are not cached. */
DBUG_ASSERT(flags.protocol_type != (unsigned int) Protocol::PROTOCOL_LOCAL);
- flags.more_results_exists= test(thd->server_status &
- SERVER_MORE_RESULTS_EXISTS);
+ flags.more_results_exists= MY_TEST(thd->server_status &
+ SERVER_MORE_RESULTS_EXISTS);
flags.in_trans= thd->in_active_multi_stmt_transaction();
- flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
+ flags.autocommit= MY_TEST(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
flags.pkt_nr= net->pkt_nr;
flags.character_set_client_num=
thd->variables.character_set_client->number;
@@ -1640,6 +1647,41 @@ send_data_in_chunks(NET *net, const uchar *packet, ulong len)
#endif
+/**
+ Build a normalized table name suitable for query cache engine callback
+
+ This consist of normalized directory '/' normalized_file_name
+ followed by suffix.
+ Suffix is needed for partitioned tables.
+*/
+
+size_t build_normalized_name(char *buff, size_t bufflen,
+ const char *db, size_t db_len,
+ const char *table_name, size_t table_len,
+ size_t suffix_len)
+{
+ uint errors;
+ size_t length;
+ char *pos= buff, *end= buff+bufflen;
+ DBUG_ENTER("build_normalized_name");
+
+ (*pos++)= FN_LIBCHAR;
+ length= strconvert(system_charset_info, db, db_len,
+ &my_charset_filename, pos, bufflen - 3,
+ &errors);
+ pos+= length;
+ (*pos++)= FN_LIBCHAR;
+ length= strconvert(system_charset_info, table_name, table_len,
+ &my_charset_filename, pos, (uint) (end - pos),
+ &errors);
+ pos+= length;
+ if (pos + suffix_len < end)
+ pos= strmake(pos, table_name + table_len, suffix_len);
+
+ DBUG_RETURN((size_t) (pos - buff));
+}
+
+
/*
Check if the query is in the cache. If it was cached, send it
to the user.
@@ -1858,18 +1900,18 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
DBUG_PRINT("qcache", ("No active database"));
}
- thd_proc_info(thd, "checking query cache for query");
+ 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= test(thd->client_capabilities & CLIENT_LONG_FLAG);
- flags.client_protocol_41= test(thd->client_capabilities &
- CLIENT_PROTOCOL_41);
+ flags.client_long_flag= MY_TEST(thd->client_capabilities & CLIENT_LONG_FLAG);
+ flags.client_protocol_41= MY_TEST(thd->client_capabilities &
+ CLIENT_PROTOCOL_41);
flags.protocol_type= (unsigned int) thd->protocol->type();
- flags.more_results_exists= test(thd->server_status &
- SERVER_MORE_RESULTS_EXISTS);
+ flags.more_results_exists= MY_TEST(thd->server_status &
+ SERVER_MORE_RESULTS_EXISTS);
flags.in_trans= thd->in_active_multi_stmt_transaction();
- flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
+ flags.autocommit= MY_TEST(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
flags.pkt_nr= thd->net.pkt_nr;
flags.character_set_client_num= thd->variables.character_set_client->number;
flags.character_set_results_num=
@@ -1949,7 +1991,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
// Check access;
- thd_proc_info(thd, "checking privileges on cached query");
+ THD_STAGE_INFO(thd, stage_checking_privileges_on_cached_query);
block_table= query_block->table(0);
block_table_end= block_table+query_block->n_tables;
for (; block_table != block_table_end; block_table++)
@@ -2013,40 +2055,55 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
engine_data= table->engine_data();
- if (table->callback() &&
- !(*table->callback())(thd, table->db(),
- table->key_length(),
- &engine_data))
+ if (table->callback())
{
- DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
- table_list.db, table_list.alias));
- BLOCK_UNLOCK_RD(query_block);
- if (engine_data != table->engine_data())
- {
- DBUG_PRINT("qcache",
- ("Handler require invalidation queries of %s.%s %lu-%lu",
- table_list.db, table_list.alias,
- (ulong) engine_data, (ulong) table->engine_data()));
- invalidate_table_internal(thd,
- (uchar *) table->db(),
- table->key_length());
- }
- else
+ char qcache_se_key_name[FN_REFLEN + 10];
+ uint qcache_se_key_len, db_length= strlen(table->db());
+ engine_data= table->engine_data();
+
+ qcache_se_key_len= build_normalized_name(qcache_se_key_name,
+ sizeof(qcache_se_key_name),
+ table->db(),
+ db_length,
+ table->table(),
+ table->key_length() -
+ db_length - 2 -
+ table->suffix_length(),
+ table->suffix_length());
+
+ if (!(*table->callback())(thd, qcache_se_key_name,
+ qcache_se_key_len, &engine_data))
{
+ DBUG_PRINT("qcache", ("Handler does not allow caching for %.*s",
+ qcache_se_key_len, qcache_se_key_name));
+ BLOCK_UNLOCK_RD(query_block);
+ if (engine_data != table->engine_data())
+ {
+ DBUG_PRINT("qcache",
+ ("Handler require invalidation queries of %.*s %lu-%lu",
+ qcache_se_key_len, qcache_se_key_name,
+ (ulong) engine_data, (ulong) table->engine_data()));
+ invalidate_table_internal(thd,
+ (uchar *) table->db(),
+ table->key_length());
+ }
+ else
+ {
+ /*
+ 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
+ }
/*
- As this can change from call to call, don't reset set
- thd->lex->safe_to_cache_query
+ End the statement transaction potentially started by engine.
+ Currently our engines do not request rollback from callbacks.
+ If this is going to change code needs to be reworked.
*/
- thd->query_cache_is_applicable= 0; // Query can't be cached
+ DBUG_ASSERT(! thd->transaction_rollback_request);
+ trans_rollback_stmt(thd);
+ goto err_unlock; // Parse query
}
- /*
- End the statement transaction potentially started by engine.
- Currently our engines do not request rollback from callbacks.
- If this is going to change code needs to be reworked.
- */
- DBUG_ASSERT(! thd->transaction_rollback_request);
- trans_rollback_stmt(thd);
- goto err_unlock; // Parse query
}
else
DBUG_PRINT("qcache", ("handler allow caching %s,%s",
@@ -2060,7 +2117,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
Send cached result to client
*/
#ifndef EMBEDDED_LIBRARY
- thd_proc_info(thd, "sending cached result to client");
+ THD_STAGE_INFO(thd, stage_sending_cached_result_to_client);
do
{
DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)",
@@ -2085,13 +2142,13 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
#endif /*!EMBEDDED_LIBRARY*/
- thd->sent_row_count= thd->limit_found_rows = query->found_rows();
+ thd->set_sent_row_count(thd->limit_found_rows = query->found_rows());
thd->status_var.last_query_cost= 0.0;
thd->query_plan_flags= (thd->query_plan_flags & ~QPLAN_QC_NO) | QPLAN_QC;
- if (!thd->sent_row_count)
+ if (!thd->get_sent_row_count())
status_var_increment(thd->status_var.empty_queries);
else
- status_var_add(thd->status_var.rows_sent, thd->sent_row_count);
+ status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());
/*
End the statement transaction potentially started by an
@@ -2100,8 +2157,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
response, we can't handle it anyway.
*/
(void) trans_commit_stmt(thd);
- if (!thd->stmt_da->is_set())
- thd->stmt_da->disable_status();
+ if (!thd->get_stmt_da()->is_set())
+ thd->get_stmt_da()->disable_status();
BLOCK_UNLOCK_RD(query_block);
MYSQL_QUERY_CACHE_HIT(thd->query(), (ulong) thd->limit_found_rows);
@@ -2165,7 +2222,7 @@ void Query_cache::invalidate(THD *thd, CHANGED_TABLE_LIST *tables_used)
for (; tables_used; tables_used= tables_used->next)
{
- thd_proc_info(thd, "invalidating query cache entries (table list)");
+ THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table_list);
invalidate_table(thd, (uchar*) tables_used->key, tables_used->key_length);
DBUG_PRINT("qcache", ("db: %s table: %s", tables_used->key,
tables_used->key+
@@ -2194,7 +2251,7 @@ void Query_cache::invalidate_locked_for_write(THD *thd,
for (; tables_used; tables_used= tables_used->next_local)
{
- thd_proc_info(thd, "invalidating query cache entries (table)");
+ THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table);
if (tables_used->lock_type >= TL_WRITE_ALLOW_WRITE &&
tables_used->table)
{
@@ -2253,6 +2310,8 @@ void Query_cache::invalidate(THD *thd, char *db)
if (is_disabled())
DBUG_VOID_RETURN;
+ DBUG_ASSERT(ok_for_lower_case_names(db));
+
bool restart= FALSE;
/*
Lock the query cache and queue all invalidation attempts to avoid
@@ -2322,6 +2381,9 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
{
DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+
/* Calculate the key outside the lock to make the lock shorter */
char key[MAX_DBKEY_LENGTH];
uint32 db_length;
@@ -2916,7 +2978,7 @@ Query_cache::write_block_data(ulong data_len, uchar* data,
DBUG_ENTER("Query_cache::write_block_data");
DBUG_PRINT("qcache", ("data: %ld, header: %ld, all header: %ld",
data_len, header_len, all_headers_len));
- Query_cache_block *block= allocate_block(max(align_len,
+ Query_cache_block *block= allocate_block(MY_MAX(align_len,
min_allocation_unit),1, 0);
if (block != 0)
{
@@ -2971,7 +3033,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
ulong append_min = get_min_append_result_data_size();
if (last_block_free_space < data_len &&
append_next_free_block(last_block,
- max(tail, append_min)))
+ MY_MAX(tail, append_min)))
last_block_free_space = last_block->length - last_block->used;
// If no space in last block (even after join) allocate new block
if (last_block_free_space < data_len)
@@ -2999,7 +3061,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
// Now finally write data to the last block
if (success && last_block_free_space > 0)
{
- ulong to_copy = min(data_len,last_block_free_space);
+ ulong to_copy = MY_MIN(data_len,last_block_free_space);
DBUG_PRINT("qcache", ("use free space %lub at block 0x%lx to copy %lub",
last_block_free_space, (ulong)last_block, to_copy));
memcpy((uchar*) last_block + last_block->used, data, to_copy);
@@ -3087,8 +3149,8 @@ inline ulong Query_cache::get_min_first_result_data_size()
if (queries_in_cache < QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER)
return min_result_data_size;
ulong avg_result = (query_cache_size - free_memory) / queries_in_cache;
- avg_result = min(avg_result, query_cache_limit);
- return max(min_result_data_size, avg_result);
+ avg_result = MY_MIN(avg_result, query_cache_limit);
+ return MY_MAX(min_result_data_size, avg_result);
}
inline ulong Query_cache::get_min_append_result_data_size()
@@ -3120,7 +3182,7 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
ulong len= data_len + all_headers_len;
ulong align_len= ALIGN_SIZE(len);
- if (!(new_block= allocate_block(max(min_size, align_len),
+ if (!(new_block= allocate_block(MY_MAX(min_size, align_len),
min_result_data_size == 0,
all_headers_len + min_result_data_size)))
{
@@ -3129,7 +3191,7 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
}
new_block->n_tables = 0;
- new_block->used = min(len, new_block->length);
+ new_block->used = MY_MIN(len, new_block->length);
new_block->type = Query_cache_block::RES_INCOMPLETE;
new_block->next = new_block->prev = new_block;
Query_cache_result *header = new_block->result();
@@ -3170,11 +3232,9 @@ void Query_cache::invalidate_table(THD *thd, TABLE_LIST *table_list)
invalidate_table(thd, table_list->table); // Table is open
else
{
- char key[MAX_DBKEY_LENGTH];
+ const char *key;
uint key_length;
-
- key_length= create_table_def_key(key, table_list->db,
- table_list->table_name);
+ key_length= get_table_def_key(table_list, &key);
// We don't store temporary tables => no key_length+=4 ...
invalidate_table(thd, (uchar *)key, key_length);
@@ -3287,18 +3347,17 @@ Query_cache::register_tables_from_list(THD *thd, TABLE_LIST *tables_used,
(*block_table)->n= n;
if (tables_used->view)
{
- char key[MAX_DBKEY_LENGTH];
+ const char *key;
uint key_length;
DBUG_PRINT("qcache", ("view: %s db: %s",
tables_used->view_name.str,
tables_used->view_db.str));
- key_length= create_table_def_key(key, tables_used->view_db.str,
- tables_used->view_name.str);
+ key_length= get_table_def_key(tables_used, &key);
/*
There are not callback function for for VIEWs
*/
if (!insert_table(key_length, key, (*block_table),
- tables_used->view_db.length,
+ tables_used->view_db.length, 0,
HA_CACHE_TBL_NONTRANSACT, 0, 0, TRUE))
DBUG_RETURN(0);
/*
@@ -3319,7 +3378,7 @@ Query_cache::register_tables_from_list(THD *thd, 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),
- tables_used->db_length,
+ tables_used->db_length, 0,
tables_used->table->file->table_cache_type(),
tables_used->callback_func,
tables_used->engine_data,
@@ -3369,7 +3428,7 @@ my_bool Query_cache::register_all_tables(THD *thd,
if (block_table->parent)
unlink_table(block_table);
}
- return test(n);
+ return MY_TEST(n);
}
@@ -3382,9 +3441,10 @@ my_bool Query_cache::register_all_tables(THD *thd,
*/
my_bool
-Query_cache::insert_table(uint key_len, char *key,
+Query_cache::insert_table(uint key_len, const char *key,
Query_cache_block_table *node,
- uint32 db_length, uint8 cache_type,
+ uint32 db_length, uint8 suffix_length_arg,
+ uint8 cache_type,
qc_engine_callback callback,
ulonglong engine_data,
my_bool hash)
@@ -3459,6 +3519,7 @@ Query_cache::insert_table(uint key_len, char *key,
char *db= header->db();
header->table(db + db_length + 1);
header->key_length(key_len);
+ header->suffix_length(suffix_length_arg);
header->type(cache_type);
header->callback(callback);
header->engine_data(engine_data);
@@ -3535,7 +3596,7 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min)
DBUG_PRINT("qcache", ("len %lu, not less %d, min %lu",
len, not_less,min));
- if (len >= min(query_cache_size, query_cache_limit))
+ if (len >= MY_MIN(query_cache_size, query_cache_limit))
{
DBUG_PRINT("qcache", ("Query cache hase only %lu memory and limit %lu",
query_cache_size, query_cache_limit));
@@ -4067,7 +4128,7 @@ Query_cache::is_cacheable(THD *thd, LEX *lex,
(long) OPTION_TO_QUERY_CACHE,
(long) lex->select_lex.options,
(int) thd->variables.query_cache_type,
- (uint) test(qc_is_able_to_intercept_result(thd))));
+ (uint) MY_TEST(qc_is_able_to_intercept_result(thd))));
DBUG_RETURN(0);
}
@@ -4096,13 +4157,13 @@ my_bool Query_cache::ask_handler_allowance(THD *thd,
continue;
handler= table->file;
if (!handler->register_query_cache_table(thd,
- table->s->table_cache_key.str,
- table->s->table_cache_key.length,
+ table->s->normalized_path.str,
+ table->s->normalized_path.length,
&tables_used->callback_func,
&tables_used->engine_data))
{
- DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
- tables_used->db, tables_used->alias));
+ DBUG_PRINT("qcache", ("Handler does not allow caching for %s",
+ table->s->normalized_path.str));
/*
As this can change from call to call, don't reset set
thd->lex->safe_to_cache_query
@@ -4521,7 +4582,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path,
DBUG_PRINT("qcache", ("table '%-.*s.%s'", *db_length, dbname, filename));
DBUG_RETURN((uint) (strmake(strmake(key, dbname,
- min(*db_length, NAME_LEN)) + 1,
+ MY_MIN(*db_length, NAME_LEN)) + 1,
filename, NAME_LEN) - key) + 1);
}