MDEV-249 QUERY CACHE INFORMATION
This commit is contained in:
parent
e73f13a707
commit
01fd55ccae
15
mysql-test/suite/plugins/r/qc_info.result
Normal file
15
mysql-test/suite/plugins/r/qc_info.result
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
set global query_cache_size=1355776;
|
||||||
|
create table t1 (a int not null);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
select * from t1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
|
||||||
|
statement_schema statement_text result_blocks_count result_blocks_size
|
||||||
|
test select * from t1 1 512
|
||||||
|
drop table t1;
|
||||||
|
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
|
||||||
|
statement_schema statement_text result_blocks_count result_blocks_size
|
||||||
|
set global query_cache_size= default;
|
23
mysql-test/suite/plugins/r/qc_info_priv.result
Normal file
23
mysql-test/suite/plugins/r/qc_info_priv.result
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
set global query_cache_size=1355776;
|
||||||
|
create table t1 (a int not null);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
select * from t1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
|
||||||
|
statement_schema statement_text result_blocks_count result_blocks_size
|
||||||
|
test select * from t1 1 512
|
||||||
|
create user mysqltest;
|
||||||
|
select a from t1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
select count(*) from information_schema.query_cache_info;
|
||||||
|
count(*)
|
||||||
|
0
|
||||||
|
drop user mysqltest;
|
||||||
|
drop table t1;
|
||||||
|
set global query_cache_size= default;
|
8
mysql-test/suite/plugins/t/qc_info.test
Normal file
8
mysql-test/suite/plugins/t/qc_info.test
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
--source qc_info_init.inc
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
# the query was invalidated
|
||||||
|
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
|
||||||
|
|
||||||
|
set global query_cache_size= default;
|
||||||
|
|
12
mysql-test/suite/plugins/t/qc_info_init.inc
Normal file
12
mysql-test/suite/plugins/t/qc_info_init.inc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
if (`select count(*) = 0 from information_schema.plugins where plugin_name = 'query_cache_info' and plugin_status='active'`)
|
||||||
|
{
|
||||||
|
--skip QUERY_CACHE_INFO plugin is not active
|
||||||
|
}
|
||||||
|
|
||||||
|
set global query_cache_size=1355776;
|
||||||
|
|
||||||
|
create table t1 (a int not null);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
select * from t1;
|
||||||
|
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
|
||||||
|
|
2
mysql-test/suite/plugins/t/qc_info_init.opt
Normal file
2
mysql-test/suite/plugins/t/qc_info_init.opt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
--loose-query_cache_info
|
||||||
|
--plugin-load=$QUERY_CACHE_INFO_SO
|
15
mysql-test/suite/plugins/t/qc_info_priv.test
Normal file
15
mysql-test/suite/plugins/t/qc_info_priv.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
|
--source qc_info_init.inc
|
||||||
|
|
||||||
|
# try an unprivileged user
|
||||||
|
create user mysqltest;
|
||||||
|
connect (conn1,localhost,mysqltest,,);
|
||||||
|
connection conn1;
|
||||||
|
select a from t1;
|
||||||
|
select count(*) from information_schema.query_cache_info;
|
||||||
|
connection default;
|
||||||
|
drop user mysqltest;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
set global query_cache_size= default;
|
||||||
|
|
@ -23,8 +23,11 @@ perl;
|
|||||||
datadir slave-load-tmpdir tmpdir socket/;
|
datadir slave-load-tmpdir tmpdir socket/;
|
||||||
|
|
||||||
# Plugins which may or may not be there:
|
# Plugins which may or may not be there:
|
||||||
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster feedback debug temp-pool ssl des-key-file
|
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster
|
||||||
xtradb thread-concurrency super-large-pages mutex-deadlock-detector null-audit maria aria pbxt oqgraph sphinx thread-handling thread-pool/;
|
feedback debug temp-pool ssl des-key-file
|
||||||
|
xtradb thread-concurrency super-large-pages
|
||||||
|
mutex-deadlock-detector null-audit maria aria pbxt oqgraph
|
||||||
|
sphinx thread-handling thread-pool query-cache-info/;
|
||||||
|
|
||||||
# And substitute the content some environment variables with their
|
# And substitute the content some environment variables with their
|
||||||
# names:
|
# names:
|
||||||
|
4
plugin/qc_info/CMakeLists.txt
Normal file
4
plugin/qc_info/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex
|
||||||
|
${CMAKE_SOURCE_DIR}/extra/yassl/include)
|
||||||
|
|
||||||
|
MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc)
|
213
plugin/qc_info/qc_info.cc
Normal file
213
plugin/qc_info/qc_info.cc
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2008, Roland Bouman
|
||||||
|
http://rpbouman.blogspot.com/
|
||||||
|
roland.bouman@gmail.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the Roland Bouman nor the
|
||||||
|
names of the contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: report query cache flags
|
||||||
|
*/
|
||||||
|
#ifndef MYSQL_SERVER
|
||||||
|
#define MYSQL_SERVER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sql_cache.h>
|
||||||
|
#include <sql_parse.h> // check_global_access
|
||||||
|
#include <sql_acl.h> // PROCESS_ACL
|
||||||
|
#include <sql_class.h> // THD
|
||||||
|
#include <table.h> // ST_SCHEMA_TABLE
|
||||||
|
#include <mysql/plugin.h>
|
||||||
|
|
||||||
|
class Accessible_Query_Cache : public Query_cache {
|
||||||
|
public:
|
||||||
|
HASH *get_queries()
|
||||||
|
{
|
||||||
|
return &this->queries;
|
||||||
|
}
|
||||||
|
} *qc;
|
||||||
|
|
||||||
|
bool schema_table_store_record(THD *thd, TABLE *table);
|
||||||
|
|
||||||
|
#define MAX_STATEMENT_TEXT_LENGTH 32767
|
||||||
|
#define COLUMN_STATEMENT_SCHEMA 0
|
||||||
|
#define COLUMN_STATEMENT_TEXT 1
|
||||||
|
#define COLUMN_RESULT_BLOCKS_COUNT 2
|
||||||
|
#define COLUMN_RESULT_BLOCKS_SIZE 3
|
||||||
|
#define COLUMN_RESULT_BLOCKS_SIZE_USED 4
|
||||||
|
|
||||||
|
/* ST_FIELD_INFO is defined in table.h */
|
||||||
|
static ST_FIELD_INFO qc_info_fields[]=
|
||||||
|
{
|
||||||
|
{"STATEMENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||||
|
{"STATEMENT_TEXT", MAX_STATEMENT_TEXT_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0},
|
||||||
|
{"RESULT_BLOCKS_COUNT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0},
|
||||||
|
{"RESULT_BLOCKS_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0},
|
||||||
|
{"RESULT_BLOCKS_SIZE_USED", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0},
|
||||||
|
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
|
||||||
|
COND *cond)
|
||||||
|
{
|
||||||
|
int status= 1;
|
||||||
|
CHARSET_INFO *scs= system_charset_info;
|
||||||
|
TABLE *table= tables->table;
|
||||||
|
HASH *queries = qc->get_queries();
|
||||||
|
|
||||||
|
/* one must have PROCESS privilege to see others' queries */
|
||||||
|
if (check_global_access(thd, PROCESS_ACL, true))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (qc->try_lock(thd))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
/* loop through all queries in the query cache */
|
||||||
|
for (uint i= 0; i < queries->records; i++)
|
||||||
|
{
|
||||||
|
const uchar *query_cache_block_raw;
|
||||||
|
Query_cache_block* query_cache_block;
|
||||||
|
Query_cache_query* query_cache_query;
|
||||||
|
uint result_blocks_count;
|
||||||
|
ulonglong result_blocks_size;
|
||||||
|
ulonglong result_blocks_size_used;
|
||||||
|
Query_cache_block *first_result_block;
|
||||||
|
Query_cache_block *result_block;
|
||||||
|
const char *statement_text;
|
||||||
|
size_t statement_text_length;
|
||||||
|
const char *key, *db;
|
||||||
|
size_t key_length, db_length;
|
||||||
|
|
||||||
|
query_cache_block_raw = my_hash_element(queries, i);
|
||||||
|
query_cache_block = (Query_cache_block*)query_cache_block_raw;
|
||||||
|
if (query_cache_block->type != Query_cache_block::QUERY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
query_cache_query = query_cache_block->query();
|
||||||
|
|
||||||
|
/* Get the actual SQL statement for this query cache query */
|
||||||
|
statement_text = (const char*)query_cache_query->query();
|
||||||
|
statement_text_length = strlen(statement_text);
|
||||||
|
/* We truncate SQL statements up to MAX_STATEMENT_TEXT_LENGTH in our I_S table */
|
||||||
|
table->field[COLUMN_STATEMENT_TEXT]->store((char*)statement_text,
|
||||||
|
min(statement_text_length, MAX_STATEMENT_TEXT_LENGTH), scs);
|
||||||
|
|
||||||
|
/* get the entire key that identifies this query cache query */
|
||||||
|
key = (const char*)query_cache_query_get_key(query_cache_block_raw,
|
||||||
|
&key_length, 0);
|
||||||
|
/* The database against which the statement is executed is part of the
|
||||||
|
query cache query key
|
||||||
|
*/
|
||||||
|
compile_time_assert(QUERY_CACHE_DB_LENGTH_SIZE == 2);
|
||||||
|
db= key + statement_text_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE;
|
||||||
|
db_length= uint2korr(db - QUERY_CACHE_DB_LENGTH_SIZE);
|
||||||
|
|
||||||
|
table->field[COLUMN_STATEMENT_SCHEMA]->store(db, db_length, scs);
|
||||||
|
|
||||||
|
/* If we have result blocks, process them */
|
||||||
|
first_result_block= query_cache_query->result();
|
||||||
|
if(first_result_block)
|
||||||
|
{
|
||||||
|
/* initialize so we can loop over the result blocks*/
|
||||||
|
result_block= first_result_block;
|
||||||
|
result_blocks_count = 1;
|
||||||
|
result_blocks_size = result_block->length;
|
||||||
|
result_blocks_size_used = result_block->used;
|
||||||
|
|
||||||
|
/* loop over the result blocks*/
|
||||||
|
while((result_block= result_block->next)!=first_result_block)
|
||||||
|
{
|
||||||
|
/* calculate total number of result blocks */
|
||||||
|
result_blocks_count++;
|
||||||
|
/* calculate total size of result blocks */
|
||||||
|
result_blocks_size += result_block->length;
|
||||||
|
/* calculate total of used size of result blocks */
|
||||||
|
result_blocks_size_used += result_block->used;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result_blocks_count = 0;
|
||||||
|
result_blocks_size = 0;
|
||||||
|
result_blocks_size_used = 0;
|
||||||
|
}
|
||||||
|
table->field[COLUMN_RESULT_BLOCKS_COUNT]->store(result_blocks_count, 0);
|
||||||
|
table->field[COLUMN_RESULT_BLOCKS_SIZE]->store(result_blocks_size, 0);
|
||||||
|
table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->store(result_blocks_size_used, 0);
|
||||||
|
|
||||||
|
if (schema_table_store_record(thd, table))
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
status = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
qc->unlock();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qc_info_plugin_init(void *p)
|
||||||
|
{
|
||||||
|
ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
|
||||||
|
|
||||||
|
schema->fields_info= qc_info_fields;
|
||||||
|
schema->fill_table= qc_info_fill_table;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
qc = (Accessible_Query_Cache *)
|
||||||
|
GetProcAddress(GetModuleHandle(NULL), "?query_cache@@3VQuery_cache@@A");
|
||||||
|
#else
|
||||||
|
qc = (Accessible_Query_Cache *)&query_cache;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return qc == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct st_mysql_information_schema qc_info_plugin=
|
||||||
|
{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
|
||||||
|
|
||||||
|
/*
|
||||||
|
Plugin library descriptor
|
||||||
|
*/
|
||||||
|
|
||||||
|
maria_declare_plugin(query_cache_info)
|
||||||
|
{
|
||||||
|
MYSQL_INFORMATION_SCHEMA_PLUGIN,
|
||||||
|
&qc_info_plugin,
|
||||||
|
"QUERY_CACHE_INFO",
|
||||||
|
"Roland Bouman",
|
||||||
|
"Lists all queries in the query cache.",
|
||||||
|
PLUGIN_LICENSE_BSD,
|
||||||
|
qc_info_plugin_init, /* Plugin Init */
|
||||||
|
0, /* Plugin Deinit */
|
||||||
|
0x0100, /* version, hex */
|
||||||
|
NULL, /* status variables */
|
||||||
|
NULL, /* system variables */
|
||||||
|
"1.0", /* version as a string */
|
||||||
|
MariaDB_PLUGIN_MATURITY_ALPHA
|
||||||
|
}
|
||||||
|
maria_declare_plugin_end;
|
||||||
|
|
@ -828,18 +828,18 @@ void Query_cache_block::destroy()
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint Query_cache_block::headers_len()
|
uint Query_cache_block::headers_len()
|
||||||
{
|
{
|
||||||
return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
|
return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
|
||||||
ALIGN_SIZE(sizeof(Query_cache_block)));
|
ALIGN_SIZE(sizeof(Query_cache_block)));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uchar* Query_cache_block::data(void)
|
uchar* Query_cache_block::data(void)
|
||||||
{
|
{
|
||||||
return (uchar*)( ((uchar*)this) + headers_len() );
|
return (uchar*)( ((uchar*)this) + headers_len() );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Query_cache_query * Query_cache_block::query()
|
Query_cache_query * Query_cache_block::query()
|
||||||
{
|
{
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (type != QUERY)
|
if (type != QUERY)
|
||||||
@ -848,7 +848,7 @@ inline Query_cache_query * Query_cache_block::query()
|
|||||||
return (Query_cache_query *) data();
|
return (Query_cache_query *) data();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Query_cache_table * Query_cache_block::table()
|
Query_cache_table * Query_cache_block::table()
|
||||||
{
|
{
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (type != TABLE)
|
if (type != TABLE)
|
||||||
@ -857,7 +857,7 @@ inline Query_cache_table * Query_cache_block::table()
|
|||||||
return (Query_cache_table *) data();
|
return (Query_cache_table *) data();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Query_cache_result * Query_cache_block::result()
|
Query_cache_result * Query_cache_block::result()
|
||||||
{
|
{
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (type != RESULT && type != RES_CONT && type != RES_BEG &&
|
if (type != RESULT && type != RES_CONT && type != RES_BEG &&
|
||||||
@ -867,7 +867,7 @@ inline Query_cache_result * Query_cache_block::result()
|
|||||||
return (Query_cache_result *) data();
|
return (Query_cache_result *) data();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
|
Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
|
||||||
{
|
{
|
||||||
return ((Query_cache_block_table *)
|
return ((Query_cache_block_table *)
|
||||||
(((uchar*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
|
(((uchar*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
|
||||||
|
@ -141,12 +141,12 @@ struct Query_cache_block
|
|||||||
inline bool is_free(void) { return type == FREE; }
|
inline bool is_free(void) { return type == FREE; }
|
||||||
void init(ulong length);
|
void init(ulong length);
|
||||||
void destroy();
|
void destroy();
|
||||||
inline uint headers_len();
|
uint headers_len();
|
||||||
inline uchar* data(void);
|
uchar* data(void);
|
||||||
inline Query_cache_query *query();
|
Query_cache_query *query();
|
||||||
inline Query_cache_table *table();
|
Query_cache_table *table();
|
||||||
inline Query_cache_result *result();
|
Query_cache_result *result();
|
||||||
inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
|
Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Query_cache_query
|
struct Query_cache_query
|
||||||
|
Loading…
x
Reference in New Issue
Block a user