diff options
author | unknown <cmiller@zippy.cornsilk.net> | 2007-07-02 07:27:39 -0400 |
---|---|---|
committer | unknown <cmiller@zippy.cornsilk.net> | 2007-07-02 07:27:39 -0400 |
commit | 358b942b20bf04a2393487b4dded9b60ac5a2ef7 (patch) | |
tree | 43cc3ae86d4795b1879f740d76ea9c9ea63a3599 | |
parent | d29f4da4fcbd1284c1fec7722f651331c7606ef9 (diff) | |
download | mariadb-git-358b942b20bf04a2393487b4dded9b60ac5a2ef7.tar.gz |
Unify profiling SHOW code and INFORMATION_SCHEMA code for
profiling. Also,
Bug#26938: profiling client hang if used before enabled
In the SHOW command, not sending header data because we had no
rows to send was a protocol violation. Porting the SHOW PROFILE
command to use the Information Schema table avoids that problem.
mysql-test/r/profiling.result:
Add headers of pre-profile SHOW test.
mysql-test/t/profiling.test:
Verify that the protocol isn't violated if we ask for profiling
info before profiling has recorded anything.
sql/sql_parse.cc:
Remove SQLCOM_SHOW_PROFILE and add a I_S schema table entry.
sql/sql_profile.cc:
Add SHOW column-names and a new function that takes profile options
set in the parser and packs a list of selected fields from the
I_S table implementation.
sql/sql_profile.h:
Remove unused functions and add a new function.
sql/sql_show.cc:
Add a pointer to the function that selects fields from I_S table
for SHOW command.
sql/sql_yacc.yy:
Prepare an I_S table for SHOW PROFILE.
sql/table.h:
Rename to match the intention.
-rw-r--r-- | mysql-test/r/profiling.result | 4 | ||||
-rw-r--r-- | mysql-test/t/profiling.test | 5 | ||||
-rw-r--r-- | sql/sql_parse.cc | 26 | ||||
-rw-r--r-- | sql/sql_profile.cc | 348 | ||||
-rw-r--r-- | sql/sql_profile.h | 7 | ||||
-rw-r--r-- | sql/sql_show.cc | 3 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 8 | ||||
-rw-r--r-- | sql/table.h | 2 |
8 files changed, 124 insertions, 279 deletions
diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index 9f478d68b8d..b99870e3564 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -1,3 +1,7 @@ +show profiles; +Query_ID Duration Query +show profile all; +Status Duration CPU_user CPU_system Context_voluntary Context_involuntary Block_ops_in Block_ops_out Messages_sent Messages_received Page_faults_major Page_faults_minor Swaps Source_function Source_file Source_line show session variables like 'profil%'; Variable_name Value profiling OFF diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index fd7562f6f16..960aa496731 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -1,3 +1,8 @@ +# Verify that the protocol isn't violated if we ask for profiling info +# before profiling has recorded anything. +show profiles; +show profile all; + # default is OFF show session variables like 'profil%'; select @@profiling; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 34702dce957..8c1d627c5f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2315,6 +2315,15 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, break; } #endif + case SCH_PROFILES: + /* + Mark this current profiling record to be discarded. We don't + wish to have SHOW commands show up in profiling. + */ +#ifdef ENABLED_PROFILING + thd->profiling.discard(); +#endif + break; case SCH_OPEN_TABLES: case SCH_VARIABLES: case SCH_STATUS: @@ -2758,23 +2767,6 @@ mysql_execute_command(THD *thd) #endif break; } - case SQLCOM_SHOW_PROFILE: - { -#ifdef ENABLED_PROFILING - thd->profiling.store(); - thd->profiling.discard(); // will get re-enabled by reset() - if (lex->profile_query_id != 0) - res= thd->profiling.show(lex->profile_options, lex->profile_query_id); - else - res= thd->profiling.show_last(lex->profile_options); - if (res) - goto error; -#else - my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling"); - goto error; -#endif - break; - } case SQLCOM_SHOW_NEW_MASTER: { if (check_global_access(thd, REPL_SLAVE_ACL)) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 91b0b062e4f..fbb05a988c5 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -41,27 +41,77 @@ int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, ST_FIELD_INFO query_profile_statistics_info[]= { /* name, length, type, value, maybe_null, old_name */ - {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"STATE", 30, MYSQL_TYPE_STRING, 0, false, NULL}, - {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, - {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, NULL}, - {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, NULL}, - {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, "Query_id"}, + {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, "Seq"}, + {"STATE", 30, MYSQL_TYPE_STRING, 0, false, "Status"}, + {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, "Duration"}, + {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, "CPU_user"}, + {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, "CPU_system"}, + {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_voluntary"}, + {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_involuntary"}, + {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_in"}, + {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_out"}, + {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, "Messages_sent"}, + {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, "Messages_received"}, + {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_major"}, + {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_minor"}, + {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, "Swaps"}, + {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, "Source_function"}, + {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, "Source_file"}, + {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, "Source_line"}, {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} }; + +int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) +{ + int profile_options = thd->lex->profile_options; + int fields_include_condition_truth_values[]= { + FALSE, /* Query_id */ + FALSE, /* Seq */ + TRUE, /* Status */ + TRUE, /* Duration */ + profile_options & PROFILE_CPU, /* CPU_user */ + profile_options & PROFILE_CPU, /* CPU_system */ + profile_options & PROFILE_CONTEXT, /* Context_voluntary */ + profile_options & PROFILE_CONTEXT, /* Context_involuntary */ + profile_options & PROFILE_BLOCK_IO, /* Block_ops_in */ + profile_options & PROFILE_BLOCK_IO, /* Block_ops_out */ + profile_options & PROFILE_IPC, /* Messages_sent */ + profile_options & PROFILE_IPC, /* Messages_received */ + profile_options & PROFILE_PAGE_FAULTS, /* Page_faults_major */ + profile_options & PROFILE_PAGE_FAULTS, /* Page_faults_minor */ + profile_options & PROFILE_SWAPS, /* Swaps */ + profile_options & PROFILE_SOURCE, /* Source_function */ + profile_options & PROFILE_SOURCE, /* Source_file */ + profile_options & PROFILE_SOURCE, /* Source_line */ + }; + + ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + int i; + + for (i= 0; schema_table->fields_info[i].field_name != NULL; i++) + { + if (! fields_include_condition_truth_values[i]) + continue; + + field_info= &schema_table->fields_info[i]; + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); + if (field) + { + field->set_name(field_info->old_name, + strlen(field_info->old_name), + system_charset_info); + if (add_item_to_list(thd, field)) + return 1; + } + } + return 0; +} + + #ifdef ENABLED_PROFILING #define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (tv).tv_usec) @@ -242,212 +292,6 @@ void QUERY_PROFILE::reset() DBUG_VOID_RETURN; } -bool QUERY_PROFILE::show(uint options) -{ - THD *thd= profiling->thd; - List<Item> field_list; - DBUG_ENTER("QUERY_PROFILE::show"); - - field_list.push_back(new Item_empty_string("Status", MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS, - MYSQL_TYPE_DOUBLE)); - - if (options & PROFILE_CPU) - { - field_list.push_back(new Item_return_int("CPU_user", TIME_FLOAT_DIGITS, - MYSQL_TYPE_DOUBLE)); - field_list.push_back(new Item_return_int("CPU_system", TIME_FLOAT_DIGITS, - MYSQL_TYPE_DOUBLE)); - } - - if (options & PROFILE_MEMORY) - { - } - - if (options & PROFILE_CONTEXT) - { - field_list.push_back(new Item_return_int("Context_voluntary", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Context_involuntary", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_BLOCK_IO) - { - field_list.push_back(new Item_return_int("Block_ops_in", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Block_ops_out", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_IPC) - { - field_list.push_back(new Item_return_int("Messages_sent", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Messages_received", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_PAGE_FAULTS) - { - field_list.push_back(new Item_return_int("Page_faults_major", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Page_faults_minor", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_SWAPS) - { - field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_SOURCE) - { - field_list.push_back(new Item_empty_string("Source_function", - MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_empty_string("Source_file", - MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_return_int("Source_line", 10, - MYSQL_TYPE_LONG)); - } - - if (thd->protocol->send_fields(&field_list, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); - - Protocol *protocol= thd->protocol; - SELECT_LEX *sel= &thd->lex->select_lex; - SELECT_LEX_UNIT *unit= &thd->lex->unit; - ha_rows idx= 0; - unit->set_limit(sel); - PROFILE_ENTRY *previous= &profile_start; - - PROFILE_ENTRY *entry; - void *iterator; - for (iterator= entries.new_iterator(); - iterator != NULL; - iterator= entries.iterator_next(iterator)) - { - entry= entries.iterator_value(iterator); - -#ifdef HAVE_GETRUSAGE - struct rusage *rusage= &(entry->rusage); -#endif - String elapsed; - - if (++idx <= unit->offset_limit_cnt) - continue; - if (idx > unit->select_limit_cnt) - break; - - protocol->prepare_for_resend(); - - /* - This entry, n, has a point in time, T(n), and a status phrase, S(n). The - status phrase S(n) describes the period of time that begins at T(n). The - previous status phrase S(n-1) describes the period of time that starts at - T(n-1) and ends at T(n). Since we want to describe the time that a status - phrase took T(n)-T(n-1), this line must describe the previous status. - */ - protocol->store(previous->status, strlen(previous->status), - system_charset_info); - protocol->store((double)(entry->time_usecs - - previous->time_usecs)/(1000.0*1000), - (uint32) TIME_FLOAT_DIGITS-1, &elapsed); - - if (options & PROFILE_CPU) - { -#ifdef HAVE_GETRUSAGE - String cpu_utime, cpu_stime; - protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, - previous->rusage.ru_utime))/(1000.0*1000), - (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); - protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, - previous->rusage.ru_stime))/(1000.0*1000), - (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_CONTEXT) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nvcsw - previous->rusage.ru_nvcsw)); - protocol->store((uint32)(rusage->ru_nivcsw - previous->rusage.ru_nivcsw)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_BLOCK_IO) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_inblock - previous->rusage.ru_inblock)); - protocol->store((uint32)(rusage->ru_oublock - previous->rusage.ru_oublock)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_IPC) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_msgsnd - previous->rusage.ru_msgsnd)); - protocol->store((uint32)(rusage->ru_msgrcv - previous->rusage.ru_msgrcv)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_PAGE_FAULTS) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_majflt - previous->rusage.ru_majflt)); - protocol->store((uint32)(rusage->ru_minflt - previous->rusage.ru_minflt)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_SWAPS) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nswap - previous->rusage.ru_nswap)); -#else - protocol->store_null(); -#endif - } - - if (options & PROFILE_SOURCE) - { - if ((entry->function != NULL) && (entry->file != NULL)) - { - protocol->store(entry->function, strlen(entry->function), - system_charset_info); - protocol->store(entry->file, strlen(entry->file), system_charset_info); - protocol->store((uint32) entry->line); - } else { - protocol->store_null(); - protocol->store_null(); - protocol->store_null(); - } - } - - if (protocol->write()) - DBUG_RETURN(TRUE); - - previous= entry; - } - send_eof(thd); - DBUG_RETURN(FALSE); -} - PROFILING::PROFILING() :profile_id_counter(1), keeping(TRUE), enabled(FALSE), current(NULL), last(NULL) { @@ -630,38 +474,11 @@ void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) DBUG_VOID_RETURN; } -bool PROFILING::show(uint options, uint profiling_query_id) -{ - DBUG_ENTER("PROFILING::show"); - QUERY_PROFILE *prof; - - void *iterator; - for (iterator= history.new_iterator(); - iterator != NULL; - iterator= history.iterator_next(iterator)) - { - prof= history.iterator_value(iterator); - - if(prof->profiling_query_id == profiling_query_id) - DBUG_RETURN(prof->show(options)); - } - - my_error(ER_WRONG_ARGUMENTS, MYF(0), "SHOW PROFILE"); - DBUG_RETURN(TRUE); -} - -bool PROFILING::show_last(uint options) -{ - DBUG_ENTER("PROFILING::show_last"); - if (!history.is_empty()) { - DBUG_RETURN(last->show(options)); - } - DBUG_RETURN(TRUE); -} - /** Fill the information schema table, "query_profile", as defined in show.cc . + There are two ways to get to this function: Selecting from the information + schema, and a SHOW command. */ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond) { @@ -696,6 +513,31 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item { entry= query->entries.iterator_value(entry_iterator); + if (thd->lex->orig_sql_command == SQLCOM_SHOW_PROFILE) + { + /* + We got here via a SHOW command. That means that we stored + information about the query we wish to show and that isn't + in a WHERE clause at a higher level to filter out rows we + wish to exclude. + + Because that functionality isn't available in the server yet, + we must filter here, at the wrong level. Once one can con- + struct where and having conditions at the SQL layer, then this + condition should be ripped out. + */ + if (thd->lex->profile_query_id == 0) /* 0 == show final query */ + { + if (query != last) + continue; + } + else + { + if (thd->lex->profile_query_id != query->profiling_query_id) + continue; + } + } + /* Set default values for this row. */ restore_record(table, s->default_values); diff --git a/sql/sql_profile.h b/sql/sql_profile.h index b82b5ce090c..56022de0dcc 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -39,6 +39,7 @@ extern const char * const _unknown_func_; extern ST_FIELD_INFO query_profile_statistics_info[]; int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); +int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); #define PROFILE_NONE 0 @@ -332,12 +333,6 @@ public: /* SHOW PROFILES */ bool show_profiles(); - /* SHOW PROFILE FOR QUERY query_id */ - bool show(uint options, uint profiling_query_id); - - /* SHOW PROFILE */ - bool show_last(uint options); - /* ... from INFORMATION_SCHEMA.PROFILING ... */ int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c59e2845c14..a26c3b41fcb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4344,7 +4344,8 @@ ST_SCHEMA_TABLE schema_tables[]= {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, {"PROFILING", query_profile_statistics_info, create_schema_table, - fill_query_profile_statistics_info, NULL, NULL, -1, -1, false}, + fill_query_profile_statistics_info, make_profile_table_for_show, + NULL, -1, -1, false}, {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 54a6a6dc462..6cff3090da3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7044,7 +7044,13 @@ show_param: | PROFILES_SYM { Lex->sql_command = SQLCOM_SHOW_PROFILES; } | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause_init - { Lex->sql_command = SQLCOM_SHOW_PROFILE; } + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SELECT; + lex->orig_sql_command= SQLCOM_SHOW_PROFILE; + if (prepare_schema_table(YYTHD, lex, NULL, SCH_PROFILES) != 0) + YYABORT; + } | opt_var_type STATUS_SYM wild_and_where { LEX *lex= Lex; diff --git a/sql/table.h b/sql/table.h index 9dbdbeb7264..c982eb90cd5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -320,7 +320,7 @@ enum enum_schema_tables SCH_COLUMN_PRIVILEGES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, - SCH_PROFILING, + SCH_PROFILES, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, |