mariadb/handler/i_s.cc
vasil e7c63e2c15 branches/zip:
Add the query in information_schema.innodb_trx.trx_query. Add it even
though it is available in information_schema.processlist.info to make
inconsistencies between those two tables obvious.

It is rather confusting to see a transaction shown in innodb_trx and
innodb_locks that holds a lock on one table and the corresponding query
in processlist executing INSERT on another table. We do not want users
to contact us asking to explain that. It is caused by the fact that the
data for innodb_* tables and processlist is fetched at different time.

Approved by:	Marko
2007-11-07 20:38:07 +00:00

1202 lines
31 KiB
C++

/******************************************************
InnoDB INFORMATION SCHEMA tables interface to MySQL.
(c) 2007 Innobase Oy
Created July 18, 2007 Vasil Dimov
*******************************************************/
#include <strings.h>
#include <mysql_priv.h>
#include <mysqld_error.h>
#include <m_ctype.h>
#include <hash.h>
#include <myisampack.h>
#include <mysys_err.h>
#include <my_sys.h>
#include "i_s.h"
#include <mysql/plugin.h>
extern "C" {
#include "trx0i_s.h"
#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
#include "buf0buddy.h" /* for i_s_zip */
#include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */
}
static const char plugin_author[] = "Innobase Oy";
#define OK(expr) \
if ((expr) != 0) { \
DBUG_RETURN(1); \
}
#if !defined __STRICT_ANSI__ && defined __GNUC__ && (__GNUC__) > 2 && !defined __INTEL_COMPILER
#define STRUCT_FLD(name, value) name: value
#else
#define STRUCT_FLD(name, value) value
#endif
static const ST_FIELD_INFO END_OF_ST_FIELD_INFO =
{STRUCT_FLD(field_name, NULL),
STRUCT_FLD(field_length, 0),
STRUCT_FLD(field_type, MYSQL_TYPE_NULL),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)};
/*
Use the following types mapping:
C type ST_FIELD_INFO::field_type
---------------------------------
long MYSQL_TYPE_LONGLONG
(field_length=MY_INT64_NUM_DECIMAL_DIGITS)
long unsigned MYSQL_TYPE_LONGLONG
(field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
char* MYSQL_TYPE_STRING
(field_length=n)
float MYSQL_TYPE_FLOAT
(field_length=0 is ignored)
void* MYSQL_TYPE_LONGLONG
(field_length=MY_INT64_NUM_DECIMAL_DIGITS, field_flags=MY_I_S_UNSIGNED)
boolean (if else) MYSQL_TYPE_LONG
(field_length=1)
time_t MYSQL_TYPE_DATETIME
(field_length=0 ignored)
---------------------------------
*/
/* XXX these are defined in mysql_priv.h inside #ifdef MYSQL_SERVER */
bool schema_table_store_record(THD *thd, TABLE *table);
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
bool check_global_access(THD *thd, ulong want_access);
/***********************************************************************
Common function to fill any of the dynamic tables:
INFORMATION_SCHEMA.innodb_trx
INFORMATION_SCHEMA.innodb_locks
INFORMATION_SCHEMA.innodb_lock_waits */
static
int
trx_i_s_common_fill_table(
/*======================*/
/* out: 0 on success */
THD* thd, /* in: thread */
TABLE_LIST* tables, /* in/out: tables to fill */
COND* cond); /* in: condition (not used) */
/***********************************************************************
Unbind a dynamic INFORMATION_SCHEMA table. */
static
int
i_s_common_deinit(
/*==============*/
/* out: 0 on success */
void* p); /* in/out: table schema object */
/***********************************************************************
Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
field. */
static
int
field_store_time_t(
/*===============*/
/* out: 0 on success */
Field* field, /* in/out: target field for storage */
time_t time) /* in: value to store */
{
MYSQL_TIME my_time;
struct tm tm_time;
#if 0
/* use this if you are sure that `variables' and `time_zone'
are always initialized */
thd->variables.time_zone->gmt_sec_to_TIME(
&my_time, (my_time_t) time);
#else
localtime_r(&time, &tm_time);
localtime_to_TIME(&my_time, &tm_time);
my_time.time_type = MYSQL_TIMESTAMP_DATETIME;
#endif
return(field->store_time(&my_time, MYSQL_TIMESTAMP_DATETIME));
}
/***********************************************************************
Auxiliary function to store char* value in MYSQL_TYPE_STRING field. */
static
int
field_store_string(
/*===============*/
/* out: 0 on success */
Field* field, /* in/out: target field for storage */
const char* str) /* in: NUL-terminated utf-8 string,
or NULL */
{
int ret;
if (str != NULL) {
ret = field->store(str, strlen(str),
system_charset_info);
field->set_notnull();
} else {
ret = 0; /* success */
field->set_null();
}
return(ret);
}
/***********************************************************************
Auxiliary function to store ulint value in MYSQL_TYPE_LONGLONG field.
If the value is ULINT_UNDEFINED then the field it set to NULL. */
static
int
field_store_ulint(
/*==============*/
/* out: 0 on success */
Field* field, /* in/out: target field for storage */
ulint n) /* in: value to store */
{
int ret;
if (n != ULINT_UNDEFINED) {
ret = field->store(n);
field->set_notnull();
} else {
ret = 0; /* success */
field->set_null();
}
return(ret);
}
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
static ST_FIELD_INFO innodb_trx_fields_info[] =
{
#define IDX_TRX_ID 0
{STRUCT_FLD(field_name, "trx_id"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_TRX_STATE 1
{STRUCT_FLD(field_name, "trx_state"),
STRUCT_FLD(field_length, TRX_QUE_STATE_STR_MAX_LEN + 1),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_TRX_STARTED 2
{STRUCT_FLD(field_name, "trx_started"),
STRUCT_FLD(field_length, 0),
STRUCT_FLD(field_type, MYSQL_TYPE_DATETIME),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_TRX_WAIT_LOCK_ID 3
{STRUCT_FLD(field_name, "trx_wait_lock_id"),
STRUCT_FLD(field_length, TRX_I_S_LOCK_ID_MAX_LEN),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_TRX_WAIT_STARTED 4
{STRUCT_FLD(field_name, "trx_wait_started"),
STRUCT_FLD(field_length, 0),
STRUCT_FLD(field_type, MYSQL_TYPE_DATETIME),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_TRX_MYSQL_THREAD_ID 5
{STRUCT_FLD(field_name, "trx_mysql_thread_id"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_TRX_QUERY 6
{STRUCT_FLD(field_name, "trx_query"),
STRUCT_FLD(field_length, TRX_I_S_TRX_QUERY_MAX_LEN),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
END_OF_ST_FIELD_INFO
};
/***********************************************************************
Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx
table with it. */
static
int
fill_innodb_trx_from_cache(
/*=======================*/
/* out: 0 on success */
trx_i_s_cache_t* cache, /* in: cache to read from */
THD* thd, /* in: used to call
schema_table_store_record() */
TABLE* table) /* in/out: fill this table */
{
Field** fields;
ulint rows_num;
char lock_id[TRX_I_S_LOCK_ID_MAX_LEN];
ulint i;
DBUG_ENTER("fill_innodb_trx_from_cache");
fields = table->field;
rows_num = trx_i_s_cache_get_rows_used(cache,
I_S_INNODB_TRX);
for (i = 0; i < rows_num; i++) {
i_s_trx_row_t* row;
row = (i_s_trx_row_t*)
trx_i_s_cache_get_nth_row(
cache, I_S_INNODB_TRX, i);
/* trx_id */
OK(fields[IDX_TRX_ID]->store(row->trx_id));
/* trx_state */
OK(field_store_string(fields[IDX_TRX_STATE],
row->trx_state));
/* trx_started */
OK(field_store_time_t(fields[IDX_TRX_STARTED],
(time_t) row->trx_started));
/* trx_wait_lock_id */
/* trx_wait_started */
if (row->trx_wait_started != 0) {
OK(field_store_string(
fields[IDX_TRX_WAIT_LOCK_ID],
trx_i_s_create_lock_id(
row->wait_lock_row,
lock_id, sizeof(lock_id))));
/* field_store_string() sets it no notnull */
OK(field_store_time_t(
fields[IDX_TRX_WAIT_STARTED],
(time_t) row->trx_wait_started));
fields[IDX_TRX_WAIT_STARTED]->set_notnull();
} else {
fields[IDX_TRX_WAIT_LOCK_ID]->set_null();
fields[IDX_TRX_WAIT_STARTED]->set_null();
}
/* trx_mysql_thread_id */
OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
row->trx_mysql_thread_id));
/* trx_query */
OK(field_store_string(fields[IDX_TRX_QUERY],
row->trx_query));
OK(schema_table_store_record(thd, table));
}
DBUG_RETURN(0);
}
/***********************************************************************
Bind the dynamic table INFORMATION_SCHEMA.innodb_trx */
static
int
innodb_trx_init(
/*============*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
ST_SCHEMA_TABLE* schema;
DBUG_ENTER("innodb_trx_init");
schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = innodb_trx_fields_info;
schema->fill_table = trx_i_s_common_fill_table;
DBUG_RETURN(0);
}
static struct st_mysql_information_schema i_s_info =
{
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
struct st_mysql_plugin i_s_innodb_trx =
{
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
/* int */
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
/* pointer to type-specific plugin descriptor */
/* void* */
STRUCT_FLD(info, &i_s_info),
/* plugin name */
/* const char* */
STRUCT_FLD(name, "innodb_trx"),
/* plugin author (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(author, plugin_author),
/* general descriptive text (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(descr, "InnoDB transactions"),
/* the plugin license (PLUGIN_LICENSE_XXX) */
/* int */
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
/* the function to invoke when plugin is loaded */
/* int (*)(void*); */
STRUCT_FLD(init, innodb_trx_init),
/* the function to invoke when plugin is unloaded */
/* int (*)(void*); */
STRUCT_FLD(deinit, i_s_common_deinit),
/* plugin version (for SHOW PLUGINS) */
/* unsigned int */
STRUCT_FLD(version, 0x0100 /* 1.0 */),
/* struct st_mysql_show_var* */
STRUCT_FLD(status_vars, NULL),
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
/* reserved for dependency checking */
/* void* */
STRUCT_FLD(__reserved1, NULL)
};
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_locks */
static ST_FIELD_INFO innodb_locks_fields_info[] =
{
#define IDX_LOCK_ID 0
{STRUCT_FLD(field_name, "lock_id"),
STRUCT_FLD(field_length, TRX_I_S_LOCK_ID_MAX_LEN),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_TRX_ID 1
{STRUCT_FLD(field_name, "lock_trx_id"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_MODE 2
{STRUCT_FLD(field_name, "lock_mode"),
/* S[,GAP] X[,GAP] IS[,GAP] IX[,GAP] AUTO_INC UNKNOWN */
STRUCT_FLD(field_length, 32),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_TYPE 3
{STRUCT_FLD(field_name, "lock_type"),
STRUCT_FLD(field_length, 32 /* RECORD|TABLE|UNKNOWN */),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_TABLE 4
{STRUCT_FLD(field_name, "lock_table"),
STRUCT_FLD(field_length, 1024),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_INDEX 5
{STRUCT_FLD(field_name, "lock_index"),
STRUCT_FLD(field_length, 1024),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_SPACE 6
{STRUCT_FLD(field_name, "lock_space"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_PAGE 7
{STRUCT_FLD(field_name, "lock_page"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_REC 8
{STRUCT_FLD(field_name, "lock_rec"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_LOCK_DATA 9
{STRUCT_FLD(field_name, "lock_data"),
STRUCT_FLD(field_length, TRX_I_S_LOCK_DATA_MAX_LEN),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
END_OF_ST_FIELD_INFO
};
/***********************************************************************
Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_locks
table with it. */
static
int
fill_innodb_locks_from_cache(
/*=========================*/
/* out: 0 on success */
trx_i_s_cache_t* cache, /* in: cache to read from */
THD* thd, /* in: used to call
schema_table_store_record() */
TABLE* table) /* in/out: fill this table */
{
Field** fields;
ulint rows_num;
char lock_id[TRX_I_S_LOCK_ID_MAX_LEN];
ulint i;
DBUG_ENTER("fill_innodb_locks_from_cache");
fields = table->field;
rows_num = trx_i_s_cache_get_rows_used(cache,
I_S_INNODB_LOCKS);
for (i = 0; i < rows_num; i++) {
i_s_locks_row_t* row;
row = (i_s_locks_row_t*)
trx_i_s_cache_get_nth_row(
cache, I_S_INNODB_LOCKS, i);
/* lock_id */
trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id));
OK(field_store_string(fields[IDX_LOCK_ID],
lock_id));
/* lock_trx_id */
OK(fields[IDX_LOCK_TRX_ID]->store(row->lock_trx_id));
/* lock_mode */
OK(field_store_string(fields[IDX_LOCK_MODE],
row->lock_mode));
/* lock_type */
OK(field_store_string(fields[IDX_LOCK_TYPE],
row->lock_type));
/* lock_table */
OK(field_store_string(fields[IDX_LOCK_TABLE],
row->lock_table));
/* lock_index */
OK(field_store_string(fields[IDX_LOCK_INDEX],
row->lock_index));
/* lock_space */
OK(field_store_ulint(fields[IDX_LOCK_SPACE],
row->lock_space));
/* lock_page */
OK(field_store_ulint(fields[IDX_LOCK_PAGE],
row->lock_page));
/* lock_rec */
OK(field_store_ulint(fields[IDX_LOCK_REC],
row->lock_rec));
/* lock_data */
OK(field_store_string(fields[IDX_LOCK_DATA],
row->lock_data));
OK(schema_table_store_record(thd, table));
}
DBUG_RETURN(0);
}
/***********************************************************************
Bind the dynamic table INFORMATION_SCHEMA.innodb_locks */
static
int
innodb_locks_init(
/*==============*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
ST_SCHEMA_TABLE* schema;
DBUG_ENTER("innodb_locks_init");
schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = innodb_locks_fields_info;
schema->fill_table = trx_i_s_common_fill_table;
DBUG_RETURN(0);
}
struct st_mysql_plugin i_s_innodb_locks =
{
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
/* int */
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
/* pointer to type-specific plugin descriptor */
/* void* */
STRUCT_FLD(info, &i_s_info),
/* plugin name */
/* const char* */
STRUCT_FLD(name, "innodb_locks"),
/* plugin author (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(author, plugin_author),
/* general descriptive text (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(descr, "InnoDB conflicting locks"),
/* the plugin license (PLUGIN_LICENSE_XXX) */
/* int */
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
/* the function to invoke when plugin is loaded */
/* int (*)(void*); */
STRUCT_FLD(init, innodb_locks_init),
/* the function to invoke when plugin is unloaded */
/* int (*)(void*); */
STRUCT_FLD(deinit, i_s_common_deinit),
/* plugin version (for SHOW PLUGINS) */
/* unsigned int */
STRUCT_FLD(version, 0x0100 /* 1.0 */),
/* struct st_mysql_show_var* */
STRUCT_FLD(status_vars, NULL),
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
/* reserved for dependency checking */
/* void* */
STRUCT_FLD(__reserved1, NULL)
};
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */
static ST_FIELD_INFO innodb_lock_waits_fields_info[] =
{
#define IDX_WAIT_LOCK_ID 0
{STRUCT_FLD(field_name, "wait_lock_id"),
STRUCT_FLD(field_length, TRX_I_S_LOCK_ID_MAX_LEN),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_WAITED_LOCK_ID 1
{STRUCT_FLD(field_name, "waited_lock_id"),
STRUCT_FLD(field_length, TRX_I_S_LOCK_ID_MAX_LEN),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
END_OF_ST_FIELD_INFO
};
/***********************************************************************
Read data from cache buffer and fill the
INFORMATION_SCHEMA.innodb_lock_waits table with it. */
static
int
fill_innodb_lock_waits_from_cache(
/*==============================*/
/* out: 0 on success */
trx_i_s_cache_t* cache, /* in: cache to read from */
THD* thd, /* in: used to call
schema_table_store_record() */
TABLE* table) /* in/out: fill this table */
{
Field** fields;
ulint rows_num;
char wait_lock_id[TRX_I_S_LOCK_ID_MAX_LEN];
char waited_lock_id[TRX_I_S_LOCK_ID_MAX_LEN];
ulint i;
DBUG_ENTER("fill_innodb_lock_waits_from_cache");
fields = table->field;
rows_num = trx_i_s_cache_get_rows_used(cache,
I_S_INNODB_LOCK_WAITS);
for (i = 0; i < rows_num; i++) {
i_s_lock_waits_row_t* row;
row = (i_s_lock_waits_row_t*)
trx_i_s_cache_get_nth_row(
cache, I_S_INNODB_LOCK_WAITS, i);
/* wait_lock_id */
OK(field_store_string(
fields[IDX_WAIT_LOCK_ID],
trx_i_s_create_lock_id(
row->wait_lock_row,
wait_lock_id,
sizeof(wait_lock_id))));
/* waited_lock_id */
OK(field_store_string(
fields[IDX_WAITED_LOCK_ID],
trx_i_s_create_lock_id(
row->waited_lock_row,
waited_lock_id,
sizeof(waited_lock_id))));
OK(schema_table_store_record(thd, table));
}
DBUG_RETURN(0);
}
/***********************************************************************
Bind the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */
static
int
innodb_lock_waits_init(
/*===================*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
ST_SCHEMA_TABLE* schema;
DBUG_ENTER("innodb_lock_waits_init");
schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = innodb_lock_waits_fields_info;
schema->fill_table = trx_i_s_common_fill_table;
DBUG_RETURN(0);
}
struct st_mysql_plugin i_s_innodb_lock_waits =
{
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
/* int */
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
/* pointer to type-specific plugin descriptor */
/* void* */
STRUCT_FLD(info, &i_s_info),
/* plugin name */
/* const char* */
STRUCT_FLD(name, "innodb_lock_waits"),
/* plugin author (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(author, "Innobase Oy"),
/* general descriptive text (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(descr, "InnoDB which lock is blocking which"),
/* the plugin license (PLUGIN_LICENSE_XXX) */
/* int */
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
/* the function to invoke when plugin is loaded */
/* int (*)(void*); */
STRUCT_FLD(init, innodb_lock_waits_init),
/* the function to invoke when plugin is unloaded */
/* int (*)(void*); */
STRUCT_FLD(deinit, i_s_common_deinit),
/* plugin version (for SHOW PLUGINS) */
/* unsigned int */
STRUCT_FLD(version, 0x0100 /* 1.0 */),
/* struct st_mysql_show_var* */
STRUCT_FLD(status_vars, NULL),
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
/* reserved for dependency checking */
/* void* */
STRUCT_FLD(__reserved1, NULL)
};
/***********************************************************************
Common function to fill any of the dynamic tables:
INFORMATION_SCHEMA.innodb_trx
INFORMATION_SCHEMA.innodb_locks
INFORMATION_SCHEMA.innodb_lock_waits */
static
int
trx_i_s_common_fill_table(
/*======================*/
/* out: 0 on success */
THD* thd, /* in: thread */
TABLE_LIST* tables, /* in/out: tables to fill */
COND* cond) /* in: condition (not used) */
{
const char* table_name;
int ret;
trx_i_s_cache_t* cache;
DBUG_ENTER("trx_i_s_common_fill_table");
/* deny access to non-superusers */
if (check_global_access(thd, SUPER_ACL)) {
DBUG_RETURN(0);
}
/* minimize the number of places where global variables are
referenced */
cache = trx_i_s_cache;
/* update the cache */
trx_i_s_cache_start_write(cache);
trx_i_s_possibly_fetch_data_into_cache(cache);
trx_i_s_cache_end_write(cache);
/* which table we have to fill? */
table_name = tables->schema_table_name;
/* or table_name = tables->schema_table->table_name; */
ret = 0;
trx_i_s_cache_start_read(cache);
if (strcasecmp(table_name, "innodb_trx") == 0) {
if (fill_innodb_trx_from_cache(
cache, thd, tables->table) != 0) {
ret = 1;
}
} else if (strcasecmp(table_name, "innodb_locks") == 0) {
if (fill_innodb_locks_from_cache(
cache, thd, tables->table) != 0) {
ret = 1;
}
} else if (strcasecmp(table_name, "innodb_lock_waits") == 0) {
if (fill_innodb_lock_waits_from_cache(
cache, thd, tables->table) != 0) {
ret = 1;
}
} else {
/* huh! what happened!? */
fprintf(stderr,
"InnoDB: trx_i_s_common_fill_table() was "
"called to fill unknown table: %s.\n"
"This function only knows how to fill "
"innodb_trx, innodb_locks and "
"innodb_lock_waits tables.\n", table_name);
ret = 1;
}
trx_i_s_cache_end_read(cache);
#if 0
DBUG_RETURN(ret);
#else
/* if this function returns something else than 0 then a
deadlock occurs between the mysqld server and mysql client,
see http://bugs.mysql.com/29900 ; when that bug is resolved
we can enable the DBUG_RETURN(ret) above */
DBUG_RETURN(0);
#endif
}
/* Fields of the dynamic table information_schema.innodb_zip. */
static ST_FIELD_INFO i_s_zip_fields_info[] =
{
{STRUCT_FLD(field_name, "size"),
STRUCT_FLD(field_length, 5),
STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, "Block Size"),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "relocated"),
STRUCT_FLD(field_length, 21),
STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, "Total Number of Relocations"),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "compressed"),
STRUCT_FLD(field_length, 21),
STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, "Total Number of Compressions"),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "compressed_ok"),
STRUCT_FLD(field_length, 21),
STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, "Total Number of"
" Successful Compressions"),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "decompressed"),
STRUCT_FLD(field_length, 21),
STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, "Total Number of Decompressions"),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "used"),
STRUCT_FLD(field_length, 21),
STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, "Currently in Use"),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
END_OF_ST_FIELD_INFO
};
/***********************************************************************
Fill the dynamic table information_schema.innodb_zip or innodb_zip_reset. */
static
int
i_s_zip_fill_low(
/*=============*/
/* out: 0 on success, 1 on failure */
THD* thd, /* in: thread */
TABLE_LIST* tables, /* in/out: tables to fill */
COND* cond, /* in: condition (ignored) */
ibool reset) /* in: TRUE=reset cumulated counts */
{
TABLE* table = (TABLE *) tables->table;
int status = 0;
uint y = 0;
DBUG_ENTER("i_s_zip_fill_low");
/* deny access to non-superusers */
if (check_global_access(thd, SUPER_ACL)) {
DBUG_RETURN(0);
}
/* Determine log2(PAGE_ZIP_MIN_SIZE / 2 / BUF_BUDDY_LOW). */
for (uint r = PAGE_ZIP_MIN_SIZE / 2 / BUF_BUDDY_LOW; r >>= 1; y++);
mutex_enter(&buf_pool->mutex);
for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
table->field[0]->store(BUF_BUDDY_LOW << x);
table->field[1]->store(buf_buddy_relocated[x]);
if (reset) {
/* This is protected by buf_pool->mutex. */
buf_buddy_relocated[x] = 0;
}
if (x > y) {
/* The cumulated counts are not protected by
any mutex. Thus, some operation in page0zip.c
could increment a counter between the time we
read it and clear it. We could introduce
mutex protection, but it could cause a
measureable performance hit in page0zip.c. */
const uint i = x - y;
table->field[2]->store(page_zip_compress_count[i]);
table->field[3]->store(page_zip_compress_ok[i]);
table->field[4]->store(page_zip_decompress_count[i]);
if (reset) {
page_zip_compress_count[i] = 0;
page_zip_compress_ok[i] = 0;
page_zip_decompress_count[i] = 0;
}
} else {
table->field[2]->store(0);
table->field[3]->store(0);
table->field[4]->store(0);
}
table->field[5]->store(buf_buddy_used[x]);
if (schema_table_store_record(thd, table)) {
status = 1;
break;
}
}
mutex_exit(&buf_pool->mutex);
DBUG_RETURN(status);
}
/***********************************************************************
Fill the dynamic table information_schema.innodb_zip. */
static
int
i_s_zip_fill(
/*=========*/
/* out: 0 on success, 1 on failure */
THD* thd, /* in: thread */
TABLE_LIST* tables, /* in/out: tables to fill */
COND* cond) /* in: condition (ignored) */
{
return(i_s_zip_fill_low(thd, tables, cond, FALSE));
}
/***********************************************************************
Fill the dynamic table information_schema.innodb_zip_reset. */
static
int
i_s_zip_reset_fill(
/*===============*/
/* out: 0 on success, 1 on failure */
THD* thd, /* in: thread */
TABLE_LIST* tables, /* in/out: tables to fill */
COND* cond) /* in: condition (ignored) */
{
return(i_s_zip_fill_low(thd, tables, cond, TRUE));
}
/***********************************************************************
Bind the dynamic table information_schema.innodb_zip. */
static
int
i_s_zip_init(
/*=========*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
DBUG_ENTER("i_s_zip_init");
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = i_s_zip_fields_info;
schema->fill_table = i_s_zip_fill;
DBUG_RETURN(0);
}
/***********************************************************************
Bind the dynamic table information_schema.innodb_zip_reset. */
static
int
i_s_zip_reset_init(
/*===============*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
DBUG_ENTER("i_s_zip_reset_init");
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = i_s_zip_fields_info;
schema->fill_table = i_s_zip_reset_fill;
DBUG_RETURN(0);
}
struct st_mysql_plugin i_s_innodb_zip =
{
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
/* int */
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
/* pointer to type-specific plugin descriptor */
/* void* */
STRUCT_FLD(info, &i_s_info),
/* plugin name */
/* const char* */
STRUCT_FLD(name, "innodb_zip"),
/* plugin author (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(author, plugin_author),
/* general descriptive text (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(descr, "Statistics for the InnoDB compressed buffer pool"),
/* the plugin license (PLUGIN_LICENSE_XXX) */
/* int */
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
/* the function to invoke when plugin is loaded */
/* int (*)(void*); */
STRUCT_FLD(init, i_s_zip_init),
/* the function to invoke when plugin is unloaded */
/* int (*)(void*); */
STRUCT_FLD(deinit, i_s_common_deinit),
/* plugin version (for SHOW PLUGINS) */
/* unsigned int */
STRUCT_FLD(version, 0x0100 /* 1.0 */),
/* struct st_mysql_show_var* */
STRUCT_FLD(status_vars, NULL),
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
/* reserved for dependency checking */
/* void* */
STRUCT_FLD(__reserved1, NULL)
};
struct st_mysql_plugin i_s_innodb_zip_reset =
{
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
/* int */
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
/* pointer to type-specific plugin descriptor */
/* void* */
STRUCT_FLD(info, &i_s_info),
/* plugin name */
/* const char* */
STRUCT_FLD(name, "innodb_zip_reset"),
/* plugin author (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(author, plugin_author),
/* general descriptive text (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(descr, "Statistics for the InnoDB compressed buffer pool;"
" reset cumulated counts"),
/* the plugin license (PLUGIN_LICENSE_XXX) */
/* int */
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
/* the function to invoke when plugin is loaded */
/* int (*)(void*); */
STRUCT_FLD(init, i_s_zip_reset_init),
/* the function to invoke when plugin is unloaded */
/* int (*)(void*); */
STRUCT_FLD(deinit, i_s_common_deinit),
/* plugin version (for SHOW PLUGINS) */
/* unsigned int */
STRUCT_FLD(version, 0x0100 /* 1.0 */),
/* struct st_mysql_show_var* */
STRUCT_FLD(status_vars, NULL),
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
/* reserved for dependency checking */
/* void* */
STRUCT_FLD(__reserved1, NULL)
};
/***********************************************************************
Unbind a dynamic INFORMATION_SCHEMA table. */
static
int
i_s_common_deinit(
/*==============*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
DBUG_ENTER("i_s_common_deinit");
/* Do nothing */
DBUG_RETURN(0);
}