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
This commit is contained in:
parent
84788e278f
commit
ff8c734864
@ -17477,6 +17477,7 @@ information and a description of what it means.
|
||||
* OPTIMIZE TABLE:: @code{OPTIMIZE TABLE} Syntax
|
||||
* ANALYZE TABLE:: @code{ANALYZE TABLE} Syntax
|
||||
* FLUSH:: @code{FLUSH} Syntax
|
||||
* RESET:: @code{RESET} Syntax
|
||||
* KILL:: @code{KILL} Syntax
|
||||
* SHOW:: @code{SHOW} Syntax
|
||||
@end menu
|
||||
@ -17564,7 +17565,7 @@ If the table hasn't changed since the last @code{ANALYZE TABLE} command,
|
||||
the table will not be analysed again.
|
||||
|
||||
|
||||
@node FLUSH, KILL, ANALYZE TABLE, Database Administration
|
||||
@node FLUSH, RESET, ANALYZE TABLE, Database Administration
|
||||
@subsection @code{FLUSH} Syntax
|
||||
|
||||
@findex FLUSH
|
||||
@ -17605,7 +17606,9 @@ signal to the @code{mysqld} server.
|
||||
@item @code{PRIVILEGES} @tab Reloads the privileges from the grant tables in
|
||||
the @code{mysql} database.
|
||||
|
||||
@item @code{TABLES} @tab Closes all open tables and force all tables in use to be closed.
|
||||
@item @code{QUERY CACHE} @tab Defragment the query cache to better utilize the memory. This command will not remove any queries from the cache.
|
||||
|
||||
@item @code{TABLES} @tab Closes all open tables and force all tables in use to be closed. This also flushes the query cache.
|
||||
|
||||
@item @code{[TABLE | TABLES] table_name [,table_name...]} @tab Flushes only the given tables.
|
||||
|
||||
@ -17618,12 +17621,34 @@ You can also access each of the commands shown above with the @code{mysqladmin}
|
||||
utility, using the @code{flush-hosts}, @code{flush-logs}, @code{reload},
|
||||
or @code{flush-tables} commands.
|
||||
|
||||
Take also a look at the @code{RESET} command used with
|
||||
replication. @xref{Replication SQL}.
|
||||
Take also a look at the @code{RESET} command used with replication.
|
||||
@xref{RESET}.
|
||||
|
||||
@node RESET, KILL, FLUSH, Database Administration
|
||||
@subsection @code{RESET} Syntax
|
||||
|
||||
@example
|
||||
FLUSH flush_option [,flush_option]
|
||||
@end example
|
||||
|
||||
@node KILL, SHOW, FLUSH, Database Administration
|
||||
The @code{RESET} command is used to clear things. It also acts as an stronger
|
||||
version of the @code{FLUSH} command. @xref{FLUSH}.
|
||||
|
||||
@multitable @columnfractions .15 .85
|
||||
@item @code{MASTER}
|
||||
@tab Deletes all binary logs listed in the index file, resetting the binlog
|
||||
index file to be empty. In pre-3.23.26 versions, @code{FLUSH MASTER} (Master)
|
||||
|
||||
@item @code{SLAVE}
|
||||
@tab Makes the slave forget its replication position in the master
|
||||
logs. In pre 3.23.26 versions the command was called
|
||||
@code{FLUSH SLAVE}(Slave)
|
||||
|
||||
@item @code{QUERY CACHE}
|
||||
@tab Removes all query results from the query cache.
|
||||
@end multitable
|
||||
|
||||
@node KILL, SHOW, RESET, Database Administration
|
||||
@subsection @code{KILL} Syntax
|
||||
|
||||
@findex KILL
|
||||
|
@ -78,8 +78,9 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
|
||||
#define REFRESH_READ_LOCK 16384 /* Lock tables for read */
|
||||
#define REFRESH_FAST 32768 /* Intern flag */
|
||||
|
||||
#define REFRESH_QUERY_CACHE 65536 /* flush query cache */
|
||||
#define REFRESH_QUERY_CACHE_FREE 0x10000L /* pack query cache */
|
||||
/* RESET (remove all queries) from query cache */
|
||||
#define REFRESH_QUERY_CACHE 65536
|
||||
#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */
|
||||
|
||||
#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
|
||||
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
|
||||
|
@ -28,3 +28,8 @@ select * from t1;
|
||||
n
|
||||
345
|
||||
drop table t1;
|
||||
flush query cache;
|
||||
reset query cache;
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 0
|
||||
|
38
mysql-test/r/query_cache.result
Normal file
38
mysql-test/r/query_cache.result
Normal file
@ -0,0 +1,38 @@
|
||||
reset query cache;
|
||||
flush status;
|
||||
drop table if exists t1;
|
||||
create table t1 (a int not null);
|
||||
insert into t1 values (1),(2),(3);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
select sql_no_cache * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
select length(now()) from t1;
|
||||
length(now())
|
||||
19
|
||||
19
|
||||
19
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 1
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 1
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 1
|
||||
drop table t1;
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 0
|
@ -66,3 +66,12 @@ connection con2;
|
||||
insert into t1 values (345);
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Test that QUERY CACHE commands doesn't core dump.
|
||||
# (Normally we don't have a cache active at this point)
|
||||
#
|
||||
|
||||
flush query cache;
|
||||
reset query cache;
|
||||
show status like "Qcache_queries_in_cache";
|
||||
|
1
mysql-test/t/query_cache-master.opt
Normal file
1
mysql-test/t/query_cache-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--set-variable=query_cache_size=2M
|
26
mysql-test/t/query_cache.test
Normal file
26
mysql-test/t/query_cache.test
Normal file
@ -0,0 +1,26 @@
|
||||
#
|
||||
# Tests with query cache
|
||||
#
|
||||
|
||||
# Reset query cache variables.
|
||||
|
||||
reset query cache;
|
||||
flush status;
|
||||
drop table if exists t1;
|
||||
create table t1 (a int not null);
|
||||
insert into t1 values (1),(2),(3);
|
||||
select * from t1;
|
||||
select * from t1;
|
||||
select sql_no_cache * from t1;
|
||||
select length(now()) from t1;
|
||||
|
||||
# Only check the variables that are independent of the machine and startup
|
||||
# options
|
||||
|
||||
show status like "Qcache_queries_in_cache";
|
||||
show status like "Qcache_inserts";
|
||||
show status like "Qcache_hits";
|
||||
|
||||
drop table t1;
|
||||
|
||||
show status like "Qcache_queries_in_cache";
|
@ -46,7 +46,7 @@ $opt_loop_count=min(1000, $opt_loop_count) if ($opt_tcpip);
|
||||
$small_loop_count=$opt_loop_count/10; # For connect tests
|
||||
|
||||
print "Testing the speed of connecting to the server and sending of data\n";
|
||||
print "Connect tests are done $opt_small_loop_count and other tests $opt_loop_count times\n\n";
|
||||
print "Connect tests are done $small_loop_count times and other tests $opt_loop_count times\n\n";
|
||||
|
||||
################################# PART:1 ###################################
|
||||
####
|
||||
@ -139,7 +139,7 @@ if ($limits->{'select_without_from'})
|
||||
$sth = $dbh->do("select 10000") or die $DBI::errstr;
|
||||
}
|
||||
$end_time=new Benchmark;
|
||||
print "Time for select_simple_query_cache ($opt_loop_count): " .
|
||||
print "Time for select_simple_cache ($opt_loop_count): " .
|
||||
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
|
||||
}
|
||||
|
||||
@ -208,8 +208,24 @@ print "Time to select_1_row ($opt_loop_count): " .
|
||||
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
|
||||
|
||||
#
|
||||
# The same test, but with 2 rows.
|
||||
# Same test (as with one row) but now with a cacheable query
|
||||
#
|
||||
|
||||
$loop_time=new Benchmark;
|
||||
|
||||
for ($i=0 ; $i < $opt_loop_count ; $i++)
|
||||
{
|
||||
$sth = $dbh->do("select a,i,s from bench1") # Select * from table with 1 record
|
||||
or die $DBI::errstr;
|
||||
}
|
||||
$end_time=new Benchmark;
|
||||
print "Time to select_1_row_cache ($opt_loop_count): " .
|
||||
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
|
||||
|
||||
#
|
||||
# The same test, but with 2 rows (not cacheable).
|
||||
#
|
||||
|
||||
print "Testing select 2 rows from table\n";
|
||||
|
||||
$sth = $dbh->do("insert into bench1 values(2,200,'BBB')")
|
||||
@ -227,6 +243,10 @@ $end_time=new Benchmark;
|
||||
print "Time to select_2_rows ($opt_loop_count): " .
|
||||
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
|
||||
|
||||
#
|
||||
# Simple test to test speed of functions.
|
||||
#
|
||||
|
||||
if ($limits->{'functions'})
|
||||
{
|
||||
print "Test select with aritmetic (+)\n";
|
||||
|
@ -156,7 +156,7 @@ if ($limits->{'group_functions'})
|
||||
fetch_all_rows($dbh,"select sum(idn+100),sum(rev_idn-100) from bench1");
|
||||
}
|
||||
$end_time=new Benchmark;
|
||||
print "Time for select_query_cache ($opt_loop_count): " .
|
||||
print "Time for select_cache ($opt_loop_count): " .
|
||||
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
|
||||
|
||||
# If the database has a query cache, the following loop should be much
|
||||
@ -168,7 +168,7 @@ if ($limits->{'group_functions'})
|
||||
fetch_all_rows($dbh,"select sum(idn+$tests),sum(rev_idn-$tests) from bench1");
|
||||
}
|
||||
$end_time=new Benchmark;
|
||||
print "Time for select_query_cache2 ($opt_loop_count): " .
|
||||
print "Time for select_cache2 ($opt_loop_count): " .
|
||||
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
168
sql/sql_cache.cc
168
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user