/****************************************************** InnoDB INFORMATION SCHEMA tables interface to MySQL. (c) 2007 Innobase Oy Created July 18, 2007 Vasil Dimov *******************************************************/ #include #include #include #include #include #include #include #include #include "i_s.h" #include 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); /*********************************************************************** 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)}, 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)); 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"); /* 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"); /* 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); }