mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-249 QUERY CACHE INFORMATION
This commit is contained in:
parent
e73f13a707
commit
01fd55ccae
11 changed files with 309 additions and 14 deletions
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/;
|
||||
|
||||
# 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
|
||||
xtradb thread-concurrency super-large-pages mutex-deadlock-detector null-audit maria aria pbxt oqgraph sphinx thread-handling thread-pool/;
|
||||
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster
|
||||
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
|
||||
# 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;
|
||||
}
|
||||
|
||||
inline uint Query_cache_block::headers_len()
|
||||
uint Query_cache_block::headers_len()
|
||||
{
|
||||
return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
|
||||
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() );
|
||||
}
|
||||
|
||||
inline Query_cache_query * Query_cache_block::query()
|
||||
Query_cache_query * Query_cache_block::query()
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if (type != QUERY)
|
||||
|
@ -848,7 +848,7 @@ inline Query_cache_query * Query_cache_block::query()
|
|||
return (Query_cache_query *) data();
|
||||
}
|
||||
|
||||
inline Query_cache_table * Query_cache_block::table()
|
||||
Query_cache_table * Query_cache_block::table()
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if (type != TABLE)
|
||||
|
@ -857,7 +857,7 @@ inline Query_cache_table * Query_cache_block::table()
|
|||
return (Query_cache_table *) data();
|
||||
}
|
||||
|
||||
inline Query_cache_result * Query_cache_block::result()
|
||||
Query_cache_result * Query_cache_block::result()
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
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();
|
||||
}
|
||||
|
||||
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 *)
|
||||
(((uchar*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
|
||||
|
|
|
@ -141,12 +141,12 @@ struct Query_cache_block
|
|||
inline bool is_free(void) { return type == FREE; }
|
||||
void init(ulong length);
|
||||
void destroy();
|
||||
inline uint headers_len();
|
||||
inline uchar* data(void);
|
||||
inline Query_cache_query *query();
|
||||
inline Query_cache_table *table();
|
||||
inline Query_cache_result *result();
|
||||
inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
|
||||
uint headers_len();
|
||||
uchar* data(void);
|
||||
Query_cache_query *query();
|
||||
Query_cache_table *table();
|
||||
Query_cache_result *result();
|
||||
Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
|
||||
};
|
||||
|
||||
struct Query_cache_query
|
||||
|
|
Loading…
Reference in a new issue