summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@hundin.mysql.fi>2001-12-06 01:05:30 +0200
committerunknown <monty@hundin.mysql.fi>2001-12-06 01:05:30 +0200
commitff8c7348648b2a2e1ce14d8332c065a38a43ca0c (patch)
treeb6eaff9c9c574324b7a2aae18f5de2e52f89576c /sql
parent84788e278f97ccabe0cfe6d5b6cfcdbe1fe86c59 (diff)
downloadmariadb-git-ff8c7348648b2a2e1ce14d8332c065a38a43ca0c.tar.gz
Update of query cache code
Docs/manual.texi: Added information about RESET sql/mysql_priv.h: Fixed wrong type sql/sql_base.cc: Removed wrong info in DBUG output sql/sql_class.cc: cleanup sql/sql_parse.cc: Fixed wrong type
Diffstat (limited to 'sql')
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_base.cc18
-rw-r--r--sql/sql_cache.cc168
-rw-r--r--sql/sql_cache.h9
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_table.cc27
7 files changed, 168 insertions, 68 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 4e3757d3f23..72953cad8e8 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -277,7 +277,7 @@ bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
bool check_stack_overrun(THD *thd,char *dummy);
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables);
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables);
void table_cache_init(void);
void table_cache_free(void);
uint cached_tables(void);
@@ -697,7 +697,6 @@ void hostname_cache_refresh(void);
bool get_interval_info(const char *str,uint length,uint count,
long *values);
/* sql_cache */
-
extern bool sql_cache_init();
extern void sql_cache_free();
extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b913233806f..7f6ffd04d98 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2195,16 +2195,18 @@ int setup_ftfuncs(THD *thd)
int init_ftfuncs(THD *thd, bool no_order)
{
- List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list);
- Item_func_match *ifm;
- DBUG_PRINT("info",("Performing FULLTEXT search"));
- thd->proc_info="FULLTEXT initialization";
-
- while ((ifm=li++))
+ if (thd->lex.select_lex.ftfunc_list.elements)
{
- ifm->init_search(no_order);
- }
+ List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list);
+ Item_func_match *ifm;
+ DBUG_PRINT("info",("Performing FULLTEXT search"));
+ thd->proc_info="FULLTEXT initialization";
+ while ((ifm=li++))
+ {
+ ifm->init_search(no_order);
+ }
+ }
return 0;
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index bc9b95fe773..9b83a14c6d6 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -200,6 +200,74 @@ stored in Query_cache_memory_bin_step structure.
Free memory blocks are sorted in bins in lists with size-ascending order
(more small blocks needed frequently then bigger one).
+
+6. Packing cache.
+
+Query cache packing is divided into two operation:
+ - pack_cache
+ - join_results
+
+pack_cache moved all blocks to "top" of cache and create one block of free
+space at the "bottom":
+
+ before pack_cache after pack_cache
+ +-------------+ +-------------+
+ | query 1 | | query 1 |
+ +-------------+ +-------------+
+ | table 1 | | table 1 |
+ +-------------+ +-------------+
+ | results 1.1 | | results 1.1 |
+ +-------------+ +-------------+
+ | free | | query 2 |
+ +-------------+ +-------------+
+ | query 2 | | table 2 |
+ +-------------+ ---> +-------------+
+ | table 2 | | results 1.2 |
+ +-------------+ +-------------+
+ | results 1.2 | | results 2 |
+ +-------------+ +-------------+
+ | free | | free |
+ +-------------+ | |
+ | results 2 | | |
+ +-------------+ | |
+ | free | | |
+ +-------------+ +-------------+
+
+pack_cache scan blocks in physical address order and move every non-free
+block "higher".
+
+pack_cach remove every free block it finds. The length of the deleted block
+is accumulated to the "gap". All non free blocks should be shifted with the
+"gap" step.
+
+join_results scans all complete queries. If the results of query are not
+stored in the same block, join_results tries to move results so, that they
+are stored in one block.
+
+ before join_results after join_results
+ +-------------+ +-------------+
+ | query 1 | | query 1 |
+ +-------------+ +-------------+
+ | table 1 | | table 1 |
+ +-------------+ +-------------+
+ | results 1.1 | | free |
+ +-------------+ +-------------+
+ | query 2 | | query 2 |
+ +-------------+ +-------------+
+ | table 2 | | table 2 |
+ +-------------+ ---> +-------------+
+ | results 1.2 | | free |
+ +-------------+ +-------------+
+ | results 2 | | results 2 |
+ +-------------+ +-------------+
+ | free | | results 1 |
+ | | | |
+ | | +-------------+
+ | | | free |
+ | | | |
+ +-------------+ +-------------+
+
+If join_results allocated new block(s) then we need call pack_cache again.
*/
#include "mysql_priv.h"
@@ -377,6 +445,10 @@ void Query_cache_query::init_n_lock()
void Query_cache_query::unlock_n_destroy()
{
DBUG_ENTER("Query_cache_query::unlock_n_destroy");
+ /*
+ The following call is not needed on system where one can destroy an
+ active semaphore
+ */
this->unlock_writing();
DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block))));
@@ -465,7 +537,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
DBUG_ENTER("query_cache_insert");
#ifndef DBUG_OFF
- // Debugging method wreck may cause this
+ // Check if we have called query_cache.wreck() (which disables the cache)
if (query_cache.query_cache_size == 0)
DBUG_VOID_RETURN;
#endif
@@ -493,6 +565,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
if (!query_cache.append_result_data(&result, length, (gptr) packet,
query_block))
{
+ query_cache.refused++;
DBUG_PRINT("warning", ("Can't append data"));
header->result(result);
DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block));
@@ -517,7 +590,7 @@ void query_cache_abort(NET *net)
DBUG_ENTER("query_cache_abort");
#ifndef DBUG_OFF
- // Debugging method wreck may cause this
+ // Check if we have called query_cache.wreck() (which disables the cache)
if (query_cache.query_cache_size == 0)
DBUG_VOID_RETURN;
#endif
@@ -545,7 +618,7 @@ void query_cache_end_of_result(NET *net)
DBUG_ENTER("query_cache_end_of_result");
#ifndef DBUG_OFF
- // Debugging method wreck may cause this
+ // Check if we have called query_cache.wreck() (which disables the cache)
if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN;
#endif
@@ -603,11 +676,11 @@ Query_cache::Query_cache(ulong query_cache_limit,
uint def_table_hash_size)
:query_cache_size(0),
query_cache_limit(query_cache_limit),
+ queries_in_cache(0), hits(0), inserts(0), refused(0),
min_allocation_unit(min_allocation_unit),
min_result_data_size(min_result_data_size),
def_query_hash_size(def_query_hash_size),
def_table_hash_size(def_table_hash_size),
- queries_in_cache(0), hits(0), inserts(0), refused(0),
initialized(0)
{
ulong min_needed=(ALIGN_SIZE(sizeof(Query_cache_block)) +
@@ -622,11 +695,11 @@ Query_cache::Query_cache(ulong query_cache_limit,
ulong Query_cache::resize(ulong query_cache_size)
{
/*
- TODO: when will be realized pack() optimize case when
+ TODO:
+ When will be realized pack() optimize case when
query_cache_size < this->query_cache_size
- */
- /*
- TODO: try to copy old cache in new memory
+
+ Try to copy old cache in new memory
*/
DBUG_ENTER("Query_cache::resize");
DBUG_PRINT("qcache", ("from %lu to %lu",this->query_cache_size,
@@ -739,7 +812,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
}
}
else
- refused++;
+ statistic_increment(refused, &structure_guard_mutex);
end:
thd->query[thd->query_length]= 0; // Restore end null
@@ -834,7 +907,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/* Now lock and test that nothing changed while blocks was unlocked */
BLOCK_LOCK_RD(query_block);
- STRUCT_UNLOCK(&structure_guard_mutex);
query = query_block->query();
result_block= first_result_block= query->result();
@@ -843,6 +915,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
/* The query is probably yet processed */
DBUG_PRINT("qcache", ("query found, but no data or data incomplete"));
+ BLOCK_UNLOCK_RD(query_block);
goto err;
}
DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
@@ -863,12 +936,15 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache",
("probably no SELECT access to %s.%s => return to normal processing",
table_list.db, table_list.name));
+ BLOCK_UNLOCK_RD(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
goto err;
}
}
move_to_query_list_end(query_block);
-
hits++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
/*
Send cached result to client
*/
@@ -957,12 +1033,11 @@ void Query_cache::invalidate(Query_cache_table::query_cache_table_type type)
{
/* Store next block address defore deleting the current block */
Query_cache_block *next = table_block->next;
-
invalidate_table(table_block);
-
+#ifdef TO_BE_DELETED
if (next == table_block) // End of list
break;
-
+#endif
table_block = next;
} while (table_block != tables_blocks[type]);
}
@@ -999,10 +1074,10 @@ void Query_cache::invalidate(char *db)
Query_cache_block *next = table_block->next;
invalidate_table_in_db(table_block, db);
-
+#ifdef TO_BE_DELETED
if (table_block == next)
break;
-
+#endif
table_block = next;
} while (table_block != tables_blocks[i]);
}
@@ -1035,21 +1110,24 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
DBUG_VOID_RETURN;
}
+ /* Remove all queries from cache */
void Query_cache::flush()
{
DBUG_ENTER("Query_cache::flush");
+ STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
{
DUMP(this);
- STRUCT_LOCK(&structure_guard_mutex);
flush_cache();
DUMP(this);
- STRUCT_UNLOCK(&structure_guard_mutex);
}
+ STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
+ /* Join result in cache in 1 block (if result length > join_limit) */
+
void Query_cache::pack(ulong join_limit, uint iteration_limit)
{
DBUG_ENTER("Query_cache::pack");
@@ -1307,7 +1385,7 @@ void Query_cache::flush_cache()
my_bool Query_cache::free_old_query()
{
DBUG_ENTER("Query_cache::free_old_query");
- if (!queries_blocks)
+ if (queries_blocks)
{
/*
try_lock_writing used to prevent client because here lock
@@ -1371,6 +1449,11 @@ void Query_cache::free_query(Query_cache_block *query_block)
for (TABLE_COUNTER_TYPE i=0; i < query_block->n_tables; i++)
unlink_table(table++);
Query_cache_block *result_block = query->result();
+
+ /*
+ The following is true when query destruction was called and no results
+ in query . (query just registered and then abort/pack/flush called)
+ */
if (result_block != 0)
{
Query_cache_block *block = result_block;
@@ -1522,7 +1605,15 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block,
DBUG_ENTER("Query_cache::write_result_data");
DBUG_PRINT("qcache", ("data_len %lu",data_len));
- // Reserve block(s) for filling
+ /*
+ Reserve block(s) for filling
+ During data allocation we must have structure_guard_mutex locked.
+ As data copy is not a fast operation, it's better if we don't have
+ structure_guard_mutex locked during data coping.
+ Thus we first allocate space and lock query, then unlock
+ structure_guard_mutex and copy data.
+ */
+
my_bool success = allocate_data_chain(result_block, data_len, query_block);
if (success)
{
@@ -1975,7 +2066,6 @@ Query_cache::join_free_blocks(Query_cache_block *first_block,
exclude_from_free_memory_list(block_in_list);
second_block = first_block->pnext;
// May be was not free block
- second_block->type = Query_cache_block::FREE;
second_block->used=0;
second_block->destroy();
@@ -2254,27 +2344,30 @@ void Query_cache::pack_cache()
Query_cache_block *before = 0;
ulong gap = 0;
my_bool ok = 1;
- Query_cache_block *i = first_block;
+ Query_cache_block *block = first_block;
DBUG_ENTER("Query_cache::pack_cache");
DUMP(this);
- do
+ if (first_block)
{
- ok = move_by_type(&border, &before, &gap, i);
- i = i->pnext;
- } while (ok && i != first_block);
+ do
+ {
+ ok = move_by_type(&border, &before, &gap, block);
+ block = block->pnext;
+ } while (ok && block != first_block);
- if (border != 0)
- {
- Query_cache_block *new_block = (Query_cache_block *) border;
- new_block->init(gap);
- new_block->pnext = before->pnext;
- before->pnext = new_block;
- new_block->pprev = before;
- new_block->pnext->pprev = new_block;
- insert_into_free_memory_list(new_block);
+ if (border != 0)
+ {
+ Query_cache_block *new_block = (Query_cache_block *) border;
+ new_block->init(gap);
+ new_block->pnext = before->pnext;
+ before->pnext = new_block;
+ new_block->pprev = before;
+ new_block->pnext->pprev = new_block;
+ insert_into_free_memory_list(new_block);
+ }
+ DUMP(this);
}
- DUMP(this);
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@@ -2487,7 +2580,6 @@ void Query_cache::relink(Query_cache_block *oblock,
my_bool Query_cache::join_results(ulong join_limit)
{
- //TODO
my_bool has_moving = 0;
DBUG_ENTER("Query_cache::join_results");
@@ -2577,7 +2669,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path)
db_length= (filename - dbname) - 1;
DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename));
- DBUG_RETURN((uint) (strmov(strnmov(key, dbname, db_length) + 1,
+ DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1,
filename) -key) + 1);
}
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 09eb745e405..f5f0580d051 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -241,12 +241,12 @@ protected:
Query_cache_memory_bin *bins; // free block lists
Query_cache_memory_bin_step *steps; // bins spacing info
HASH queries, tables;
- uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin
- my_bool initialized;
-
/* options */
ulong min_allocation_unit, min_result_data_size;
uint def_query_hash_size, def_table_hash_size;
+ uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin
+
+ my_bool initialized;
/* Exclude/include from cyclic double linked list */
static void double_linked_list_exclude(Query_cache_block *point,
@@ -368,10 +368,7 @@ protected:
/* Remove all queries that uses any of the listed following table */
void invalidate_by_MyISAM_filename(const char *filename);
- /* Remove all queries from cache */
void flush();
-
- /* Join result in cache in 1 block (if result length > join_limit) */
void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT,
uint iteration_limit = QUERY_CACHE_PACK_ITERATION);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0b596c01f9d..d293a62903d 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -122,7 +122,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
server_status=SERVER_STATUS_AUTOCOMMIT;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
options=thd_startup_options;
- query_cache_type = (byte)query_cache_startup_type;
+ query_cache_type = (byte) query_cache_startup_type;
sql_mode=(uint) opt_sql_mode;
inactive_timeout=net_wait_timeout;
open_options=ha_open_options;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 769527c92fe..8eef80bc985 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -951,7 +951,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_REFRESH:
{
- uint options=(uchar) packet[0];
+ ulong options= (ulong) (uchar) packet[0];
if (check_access(thd,RELOAD_ACL,any_db))
break;
mysql_log.write(thd,command,NullS);
@@ -1432,7 +1432,6 @@ mysql_execute_command(void)
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
lex->alter_keys_onoff, lex->simple_alter);
- query_cache.invalidate(tables);
}
break;
}
@@ -2984,7 +2983,7 @@ static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
return 0;
}
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
bool result=0;
@@ -3006,12 +3005,12 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
}
if (options & REFRESH_QUERY_CACHE_FREE)
{
- query_cache.pack();
+ query_cache.pack(); // FLUSH QUERY CACHE
options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
}
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
{
- query_cache.flush();
+ query_cache.flush(); // RESET QUERY CACHE
}
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 737c8fccd9d..2f9fa17faf1 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -951,6 +951,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name);
net_store_data(packet, buff);
close_thread_tables(thd);
+ table->table=0; // For query cache
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
packet->length()))
goto err;
@@ -1028,6 +1029,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
remove_table_from_cache(thd, table->table->table_cache_key,
table->table->real_name);
close_thread_tables(thd);
+ table->table=0; // For query cache
if (my_net_write(&thd->net, (char*) packet->ptr(),
packet->length()))
goto err;
@@ -1037,9 +1039,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
DBUG_RETURN(0);
err:
close_thread_tables(thd); // Shouldn't be needed
+ if (table)
+ table->table=0;
DBUG_RETURN(-1);
}
+
int mysql_backup_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_backup_table");
@@ -1658,24 +1663,30 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
if (error)
{
- // This shouldn't happen. We solve this the safe way by
- // closing the locked table.
+ /*
+ This shouldn't happen. We solve this the safe way by
+ closing the locked table.
+ */
close_cached_table(thd,table);
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
if (thd->lock || new_name != table_name) // True if WIN32
{
- // Not table locking or alter table with rename
- // free locks and remove old table
+ /*
+ Not table locking or alter table with rename
+ free locks and remove old table
+ */
close_cached_table(thd,table);
VOID(quick_rm_table(old_db_type,db,old_name));
}
else
{
- // Using LOCK TABLES without rename.
- // This code is never executed on WIN32!
- // Remove old renamed table, reopen table and get new locks
+ /*
+ Using LOCK TABLES without rename.
+ This code is never executed on WIN32!
+ Remove old renamed table, reopen table and get new locks
+ */
if (table)
{
VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
@@ -1712,7 +1723,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
- table_list->table=0; // Table is closed
+ table_list->table=0; // For query cache
query_cache.invalidate(table_list);
end_temporary: