1 # name : response-time-distribution.patch
6 # Any small change to this file in the main branch
7 # should be done or reviewed by the maintainer!
8 diff -ruN a/include/mysql_com.h b/include/mysql_com.h
9 --- a/include/mysql_com.h 2010-11-01 08:43:53.000000000 +0000
10 +++ b/include/mysql_com.h 2010-11-01 08:52:40.000000000 +0000
12 #define REFRESH_FAST 32768 /* Intern flag */
14 /* RESET (remove all queries) from query cache */
15 -#define REFRESH_QUERY_CACHE 65536
16 -#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */
17 -#define REFRESH_DES_KEY_FILE 0x40000L
18 -#define REFRESH_USER_RESOURCES 0x80000L
19 +#define REFRESH_QUERY_CACHE 65536
20 +#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */
21 +#define REFRESH_DES_KEY_FILE 0x40000L
22 +#define REFRESH_USER_RESOURCES 0x80000L
23 +#define REFRESH_QUERY_RESPONSE_TIME 0x100000L /* response time distibution */
25 #define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
26 #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
27 diff -ruN a/patch_info/response-time-distribution.info b/patch_info/response-time-distribution.info
28 --- a/patch_info/response-time-distribution.info 1970-01-01 00:00:00.000000000 +0000
29 +++ b/patch_info/response-time-distribution.info 2010-11-01 08:52:40.000000000 +0000
31 +File=response-time-distribution.patch
32 +Name=Response time distribution
34 +Author=Percona <info@percona.com>
38 +2010-07-02 first version avaliable
39 +2010-09-15 add column 'total'
40 diff -ruN a/sql/Makefile.am b/sql/Makefile.am
41 --- a/sql/Makefile.am 2010-11-01 08:43:52.000000000 +0000
42 +++ b/sql/Makefile.am 2010-11-01 08:52:40.000000000 +0000
44 sql_repl.h slave.h rpl_filter.h rpl_injector.h \
45 log_event.h rpl_record.h \
46 log_event_old.h rpl_record_old.h \
47 - sql_sort.h sql_cache.h set_var.h \
48 + sql_sort.h sql_cache.h set_var.h query_response_time.h \
49 spatial.h gstream.h client_settings.h tzfile.h \
50 tztime.h my_decimal.h\
51 sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
53 sql_string.cc sql_manager.cc sql_map.cc \
54 mysqld.cc password.c hash_filo.cc hostname.cc \
55 sql_connect.cc scheduler.cc sql_parse.cc \
56 - set_var.cc sql_yacc.yy \
57 + set_var.cc query_response_time.cc sql_yacc.yy \
58 sql_base.cc table.cc sql_select.cc sql_insert.cc \
60 sql_prepare.cc sql_error.cc sql_locale.cc \
61 diff -ruN a/sql/Makefile.in b/sql/Makefile.in
62 --- a/sql/Makefile.in 2010-11-01 08:43:52.000000000 +0000
63 +++ b/sql/Makefile.in 2010-11-01 08:52:40.000000000 +0000
65 sql_string.$(OBJEXT) sql_manager.$(OBJEXT) sql_map.$(OBJEXT) \
66 mysqld.$(OBJEXT) password.$(OBJEXT) hash_filo.$(OBJEXT) \
67 hostname.$(OBJEXT) sql_connect.$(OBJEXT) scheduler.$(OBJEXT) \
68 - sql_parse.$(OBJEXT) set_var.$(OBJEXT) sql_yacc.$(OBJEXT) \
69 + sql_parse.$(OBJEXT) set_var.$(OBJEXT) query_response_time.${OBJEXT} sql_yacc.$(OBJEXT) \
70 sql_base.$(OBJEXT) table.$(OBJEXT) sql_select.$(OBJEXT) \
71 sql_insert.$(OBJEXT) sql_profile.$(OBJEXT) \
72 sql_prepare.$(OBJEXT) sql_error.$(OBJEXT) sql_locale.$(OBJEXT) \
74 sql_repl.h slave.h rpl_filter.h rpl_injector.h \
75 log_event.h rpl_record.h \
76 log_event_old.h rpl_record_old.h \
77 - sql_sort.h sql_cache.h set_var.h \
78 + sql_sort.h sql_cache.h set_var.h query_response_time.h \
79 spatial.h gstream.h client_settings.h tzfile.h \
80 tztime.h my_decimal.h\
81 sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
83 sql_string.cc sql_manager.cc sql_map.cc \
84 mysqld.cc password.c hash_filo.cc hostname.cc \
85 sql_connect.cc scheduler.cc sql_parse.cc \
86 - set_var.cc sql_yacc.yy \
87 + set_var.cc query_response_time.cc sql_yacc.yy \
88 sql_base.cc table.cc sql_select.cc sql_insert.cc \
90 sql_prepare.cc sql_error.cc sql_locale.cc \
92 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/password.Po@am__quote@
93 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/procedure.Po@am__quote@
94 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Po@am__quote@
95 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query_response_time.Po@am__quote@
96 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/records.Po@am__quote@
97 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_failsafe.Po@am__quote@
98 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpl_filter.Po@am__quote@
99 diff -ruN a/sql/lex.h b/sql/lex.h
100 --- a/sql/lex.h 2010-11-01 08:43:53.000000000 +0000
101 +++ b/sql/lex.h 2010-11-01 08:52:40.000000000 +0000
103 { "PURGE", SYM(PURGE)},
104 { "QUARTER", SYM(QUARTER_SYM)},
105 { "QUERY", SYM(QUERY_SYM)},
106 + { "QUERY_RESPONSE_TIME", SYM(QUERY_RESPONSE_TIME_SYM)},
107 { "QUICK", SYM(QUICK)},
108 { "RANGE", SYM(RANGE_SYM)},
109 { "READ", SYM(READ_SYM)},
110 diff -ruN a/sql/mysql_priv.h b/sql/mysql_priv.h
111 --- a/sql/mysql_priv.h 2010-11-01 08:43:57.000000000 +0000
112 +++ b/sql/mysql_priv.h 2010-11-01 08:52:40.000000000 +0000
113 @@ -2121,6 +2121,11 @@
114 extern my_bool opt_query_cache_strip_comments;
115 extern my_bool opt_use_global_long_query_time;
116 extern my_bool opt_slow_query_log_microseconds_timestamp;
117 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
118 +extern ulong opt_query_response_time_range_base;
119 +extern my_bool opt_enable_query_response_time_stats;
120 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
121 +extern SHOW_COMP_OPTION have_response_time_distribution;
122 extern my_bool sp_automatic_privileges, opt_noacl;
123 extern my_bool opt_old_style_user_limits, trust_function_creators;
124 extern uint opt_crash_binlog_innodb;
125 diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc
126 --- a/sql/mysqld.cc 2010-11-01 08:43:57.000000000 +0000
127 +++ b/sql/mysqld.cc 2010-11-01 08:52:40.000000000 +0000
130 #include "rpl_injector.h"
132 +#include "query_response_time.h"
133 #ifdef HAVE_SYS_PRCTL_H
134 #include <sys/prctl.h>
137 my_bool opt_query_cache_strip_comments = 0;
138 my_bool opt_use_global_long_query_time= 0;
139 my_bool opt_slow_query_log_microseconds_timestamp= 0;
140 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
141 +ulong opt_query_response_time_range_base = QRT_DEFAULT_BASE;
142 +my_bool opt_enable_query_response_time_stats= 0;
143 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
144 my_bool lower_case_file_system= 0;
145 my_bool opt_large_pages= 0;
146 my_bool opt_myisam_use_mmap= 0;
148 MY_LOCALE *my_default_lc_time_names;
150 SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen, have_query_cache;
151 +SHOW_COMP_OPTION have_response_time_distribution;
152 SHOW_COMP_OPTION have_geometry, have_rtree_keys;
153 SHOW_COMP_OPTION have_crypt, have_compress;
154 SHOW_COMP_OPTION have_community_features;
155 @@ -1389,6 +1395,9 @@
156 free_global_thread_stats();
157 free_global_table_stats();
158 free_global_index_stats();
159 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
160 + query_response_time_free();
161 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
162 #ifdef HAVE_REPLICATION
165 @@ -4103,6 +4112,9 @@
167 init_global_table_stats();
168 init_global_index_stats();
169 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
170 + query_response_time_init();
171 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
173 /* We have to initialize the storage engines before CSV logging */
175 @@ -5916,6 +5928,10 @@
176 OPT_USE_GLOBAL_LONG_QUERY_TIME,
177 OPT_USE_GLOBAL_LOG_SLOW_CONTROL,
178 OPT_SLOW_QUERY_LOG_MICROSECONDS_TIMESTAMP,
179 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
180 + OPT_QRT_RANGE_BASE,
181 + OPT_ENABLE_QRT_STATS,
182 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
183 OPT_IGNORE_BUILTIN_INNODB,
184 OPT_BINLOG_DIRECT_NON_TRANS_UPDATE,
185 OPT_DEFAULT_CHARACTER_SET_OLD,
186 @@ -6987,6 +7003,23 @@
187 "Use microsecond time's precision in slow query log",
188 (uchar**) &opt_slow_query_log_microseconds_timestamp, (uchar**) &opt_slow_query_log_microseconds_timestamp,
189 0, GET_BOOL, OPT_ARG, 0, 0, 1, 0, 1, 0},
190 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
191 + {"query_response_time_range_base", OPT_QRT_RANGE_BASE,
192 + "Select base of log for query_response_time ranges. WARNING: variable change affect only after flush",
193 + (uchar**) &opt_query_response_time_range_base, (uchar**) &opt_query_response_time_range_base,
194 + 0, GET_ULONG, REQUIRED_ARG,
195 + /* def_value */ QRT_DEFAULT_BASE,
197 + /* max_value */ QRT_MAXIMUM_BASE,
199 + /* block_size */ 1,
202 + {"enable_query_response_time_stats", OPT_ENABLE_QRT_STATS,
203 + "Enable or disable query response time statisics collecting",
204 + (uchar**) &opt_enable_query_response_time_stats, (uchar**) &opt_enable_query_response_time_stats,
205 + 0, GET_BOOL, REQUIRED_ARG, 0, 0, 1, 0, 1, 0},
206 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
207 {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES,
208 "If set to 1, table names are stored in lowercase on disk and table names "
209 "will be case-insensitive. Should be set to 2 if you are using a case-"
210 @@ -8208,6 +8241,11 @@
212 have_query_cache=SHOW_OPTION_NO;
214 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
215 + have_response_time_distribution= SHOW_OPTION_YES;
216 +#else /* HAVE_RESPONSE_TIME_DISTRIBUTION */
217 + have_response_time_distribution= SHOW_OPTION_NO;
218 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
220 have_geometry=SHOW_OPTION_YES;
222 diff -ruN a/sql/query_response_time.cc b/sql/query_response_time.cc
223 --- a/sql/query_response_time.cc 1970-01-01 00:00:00.000000000 +0000
224 +++ b/sql/query_response_time.cc 2010-11-02 15:34:52.000000000 +0000
227 +#include <sys/types.h>
228 +#include <machine/atomic.h>
229 +#endif // __FreeBSD__
230 +#include "my_global.h"
231 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
232 +#include "mysql_priv.h"
233 +#include "mysql_com.h"
234 +#include "rpl_tblmap.h"
235 +#include "query_response_time.h"
237 +#define TIME_STRING_POSITIVE_POWER_LENGTH QRT_TIME_STRING_POSITIVE_POWER_LENGTH
238 +#define TIME_STRING_NEGATIVE_POWER_LENGTH 6
239 +#define TOTAL_STRING_POSITIVE_POWER_LENGTH QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH
240 +#define TOTAL_STRING_NEGATIVE_POWER_LENGTH 6
241 +#define MINIMUM_BASE 2
242 +#define MAXIMUM_BASE QRT_MAXIMUM_BASE
243 +#define POSITIVE_POWER_FILLER QRT_POSITIVE_POWER_FILLER
244 +#define NEGATIVE_POWER_FILLER QRT_NEGATIVE_POWER_FILLER
245 +#define STRING_OVERFLOW QRT_STRING_OVERFLOW
246 +#define TIME_OVERFLOW QRT_TIME_OVERFLOW
247 +#define DEFAULT_BASE QRT_DEFAULT_BASE
249 +#define do_xstr(s) do_str(s)
250 +#define do_str(s) #s
251 +#define do_format(filler,width) "%" filler width "lld"
253 + Format strings for snprintf. Generate from:
254 + POSITIVE_POWER_FILLER and TIME_STRING_POSITIVE_POWER_LENGTH
255 + NEFATIVE_POWER_FILLER and TIME_STRING_NEGATIVE_POWER_LENGTH
257 +#define TIME_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TIME_STRING_POSITIVE_POWER_LENGTH))
258 +#define TIME_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TIME_STRING_NEGATIVE_POWER_LENGTH))
259 +#define TIME_STRING_FORMAT TIME_STRING_POSITIVE_POWER_FORMAT "." TIME_STRING_NEGATIVE_POWER_FORMAT
261 +#define TOTAL_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TOTAL_STRING_POSITIVE_POWER_LENGTH))
262 +#define TOTAL_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TOTAL_STRING_NEGATIVE_POWER_LENGTH))
263 +#define TOTAL_STRING_FORMAT TOTAL_STRING_POSITIVE_POWER_FORMAT "." TOTAL_STRING_NEGATIVE_POWER_FORMAT
265 +#define TIME_STRING_LENGTH QRT_TIME_STRING_LENGTH
266 +#define TIME_STRING_BUFFER_LENGTH (TIME_STRING_LENGTH + 1 /* '\0' */)
268 +#define TOTAL_STRING_LENGTH QRT_TOTAL_STRING_LENGTH
269 +#define TOTAL_STRING_BUFFER_LENGTH (TOTAL_STRING_LENGTH + 1 /* '\0' */)
272 + Calculate length of "log linear"
274 + (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) < (MINIMUM_BASE ^ (result + 1))
277 + (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH)
279 + (MINIMUM_BASE ^ (result + 1)) > (10 ^ STRING_POWER_LENGTH)
282 + result <= LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
283 + result + 1 > LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
285 + 4) STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) - 1 < result <= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
287 + MINIMUM_BASE= 2 always, LOG(MINIMUM_BASE,10)= 3.3219280948873626, result= (int)3.3219280948873626 * STRING_POWER_LENGTH
289 + Last counter always use for time overflow
291 +#define POSITIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_POSITIVE_POWER_LENGTH))
292 +#define NEGATIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_NEGATIVE_POWER_LENGTH))
293 +#define OVERALL_POWER_COUNT (NEGATIVE_POWER_COUNT + 1 + POSITIVE_POWER_COUNT)
295 +#define MILLION ((unsigned long)1000 * 1000)
297 +namespace query_response_time
303 + utility() : m_base(0)
305 + m_max_dec_value= MILLION;
306 + for(int i= 0; TIME_STRING_POSITIVE_POWER_LENGTH > i; ++i)
307 + m_max_dec_value *= 10;
308 + setup(DEFAULT_BASE);
311 + uint base() const { return m_base; }
312 + uint negative_count() const { return m_negative_count; }
313 + uint positive_count() const { return m_positive_count; }
314 + uint bound_count() const { return m_bound_count; }
315 + ulonglong max_dec_value() const { return m_max_dec_value; }
316 + ulonglong bound(uint index) const { return m_bound[ index ]; }
318 + void setup(uint base)
324 + const ulonglong million= 1000 * 1000;
325 + ulonglong value= million;
326 + m_negative_count= 0;
329 + m_negative_count += 1;
332 + m_negative_count -= 1;
335 + m_positive_count= 0;
336 + while(value < m_max_dec_value)
338 + m_positive_count += 1;
341 + m_bound_count= m_negative_count + m_positive_count;
344 + for(uint i= 0; i < m_negative_count; ++i)
347 + m_bound[m_negative_count - i - 1]= value;
350 + for(uint i= 0; i < m_positive_count; ++i)
352 + m_bound[m_negative_count + i]= value;
359 + uint m_negative_count;
360 + uint m_positive_count;
361 + uint m_bound_count;
362 + ulonglong m_max_dec_value; /* for TIME_STRING_POSITIVE_POWER_LENGTH=7 is 10000000 */
363 + ulonglong m_bound[OVERALL_POWER_COUNT];
366 +void print_time(char* buffer, std::size_t buffer_size, std::size_t string_positive_power_length, const char* format, uint64 value)
368 + memset(buffer,'X',buffer_size);
369 + buffer[string_positive_power_length]= '.';
370 + ulonglong second= (value / MILLION);
371 + ulonglong microsecond= (value % MILLION);
372 + int result_length= snprintf(buffer, buffer_size, format, second, microsecond);
373 + if(result_length < 0)
375 + assert(sizeof(STRING_OVERFLOW) <= buffer_size);
376 + memcpy(buffer, STRING_OVERFLOW, sizeof(STRING_OVERFLOW));
379 + buffer[result_length]= 0;
382 +typedef uint64 TimeCounter;
383 +void add_time_atomic(TimeCounter* counter, uint64 time)
385 + __sync_fetch_and_add(counter,time);
387 +#endif // __x86_64__
389 +inline uint32 get_high(uint64 value)
391 + return ((value >> 32) << 32);
393 +inline uint32 get_low(uint64 value)
395 + return ((value << 32) >> 32);
398 +inline bool compare_and_swap(volatile uint32 *target, uint32 old, uint32 new_value)
400 + return atomic_cmpset_32(target,old,new_value);
402 +#else // __FreeBSD__
403 +inline bool compare_and_swap(volatile uint32* target, uint32 old, uint32 new_value)
405 + return __sync_bool_compare_and_swap(target,old,new_value);
407 +#endif // __FreeBSD__
411 + TimeCounter& operator=(uint64 time)
413 + this->m_high= get_high(time);
414 + this->m_low= get_low(time);
417 + operator uint64() const
419 + return ((static_cast<uint64>(m_high) << 32) + static_cast<uint64>(m_low));
421 + void add(uint64 time)
423 + uint32 time_high = get_high(time);
424 + uint32 time_low = get_low(time);
425 + uint64 time_low64= time_low;
428 + uint32 old_low= this->m_low;
429 + uint64 old_low64= old_low;
431 + uint64 new_low64= old_low64 + time_low64;
432 + uint32 new_low= (get_low(new_low64));
433 + bool add_high= (get_high(new_low64) != 0);
435 + if(!compare_and_swap(&m_low,old_low,new_low))
445 + __sync_fetch_and_add(&m_high,time_high);
454 +void add_time_atomic(TimeCounter* counter, uint64 time)
456 + counter->add(time);
460 +class time_collector
463 + time_collector(utility& u) : m_utility(&u)
466 + uint32 count(uint index) const { return m_count[index]; }
467 + uint64 total(uint index) const { return m_total[index]; }
471 + memset(&m_count,0,sizeof(m_count));
472 + memset((void*)&m_total,0,sizeof(m_total));
474 + void collect(uint64 time)
476 + bool no_collect= false;
477 + DBUG_EXECUTE_IF("response_time_distribution_log_only_more_300_milliseconds", { \
478 + no_collect= time < 300 * 1000; \
480 + if(no_collect) return;
482 + for(int count= m_utility->bound_count(); count > i; ++i)
484 + if(m_utility->bound(i) > time)
486 + __sync_fetch_and_add(&(m_count[i]),(uint32)1);
487 + add_time_atomic(&(m_total[i]),time);
493 + utility* m_utility;
494 + uint32 m_count[OVERALL_POWER_COUNT + 1];
495 + TimeCounter m_total[OVERALL_POWER_COUNT + 1];
501 + collector() : m_time(m_utility)
503 + m_utility.setup(DEFAULT_BASE);
509 + m_utility.setup(opt_query_response_time_range_base);
512 + int fill(THD* thd, TABLE_LIST *tables, COND *cond)
514 + DBUG_ENTER("fill_schema_query_response_time");
515 + TABLE *table= static_cast<TABLE*>(tables->table);
516 + Field **fields= table->field;
517 + for(uint i= 0, count= bound_count() + 1 /* with overflow */; count > i; ++i)
519 + char time[TIME_STRING_BUFFER_LENGTH];
520 + char total[TOTAL_STRING_BUFFER_LENGTH];
521 + if(i == bound_count())
523 + assert(sizeof(TIME_OVERFLOW) <= TIME_STRING_BUFFER_LENGTH);
524 + assert(sizeof(TIME_OVERFLOW) <= TOTAL_STRING_BUFFER_LENGTH);
525 + memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
526 + memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
530 + print_time(time,sizeof(time),TIME_STRING_POSITIVE_POWER_LENGTH,TIME_STRING_FORMAT,this->bound(i));
531 + print_time(total,sizeof(total),TOTAL_STRING_POSITIVE_POWER_LENGTH,TOTAL_STRING_FORMAT,this->total(i));
533 + fields[0]->store(time,strlen(time),system_charset_info);
534 + fields[1]->store(this->count(i));
535 + fields[2]->store(total,strlen(total),system_charset_info);
536 + if (schema_table_store_record(thd, table))
543 + void collect(ulonglong time)
545 + m_time.collect(time);
547 + uint bound_count() const
549 + return m_utility.bound_count();
551 + ulonglong bound(uint index)
553 + return m_utility.bound(index);
555 + ulonglong count(uint index)
557 + return m_time.count(index);
559 + ulonglong total(uint index)
561 + return m_time.total(index);
565 + time_collector m_time;
568 +static collector g_collector;
570 +} // namespace query_response_time
572 +void query_response_time_init()
576 +void query_response_time_free()
578 + query_response_time::g_collector.flush();
581 +void query_response_time_flush()
583 + query_response_time::g_collector.flush();
585 +void query_response_time_collect(ulonglong query_time)
587 + query_response_time::g_collector.collect(query_time);
590 +int query_response_time_fill(THD* thd, TABLE_LIST *tables, COND *cond)
592 + return query_response_time::g_collector.fill(thd,tables,cond);
594 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
595 diff -ruN a/sql/query_response_time.h b/sql/query_response_time.h
596 --- a/sql/query_response_time.h 1970-01-01 00:00:00.000000000 +0000
597 +++ b/sql/query_response_time.h 2010-11-01 08:52:40.000000000 +0000
599 +#ifndef QUERY_RESPONSE_TIME_H
600 +#define QUERY_RESPONSE_TIME_H
603 + Settings for query response time
607 + Maximum string length for (10 ^ (-1 * QRT_STRING_NEGATIVE_POWER_LENGTH)) in text representation.
608 + Example: for 6 is 0.000001
611 + Maximum string length for (10 ^ (QRT_STRING_POSITIVE_POWER_LENGTH + 1) - 1) in text representation.
612 + Example: for 7 is 9999999.0
614 +#define QRT_TIME_STRING_POSITIVE_POWER_LENGTH 7
615 +#define QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH 7
618 + Minimum base for log - ALWAYS 2
619 + Maximum base for log:
621 +#define QRT_MAXIMUM_BASE 1000
624 + Filler for whole number (positive power)
626 + QRT_POSITIVE_POWER_FILLER ' '
627 + QRT_POSITIVE_POWER_LENGTH 7
628 + and number 7234 result is:
631 +#define QRT_POSITIVE_POWER_FILLER " "
633 + Filler for fractional number. Similiary to whole number
635 +#define QRT_NEGATIVE_POWER_FILLER "0"
638 + Message if string overflow (string overflow - internal error, this string say about bug in QRT)
640 +#define QRT_STRING_OVERFLOW "TOO BIG STRING"
643 + Message if time too big for statistic collecting (very long query)
645 +#define QRT_TIME_OVERFLOW "TOO LONG"
647 +#define QRT_DEFAULT_BASE 10
649 +#define QRT_TIME_STRING_LENGTH \
650 + max( (QRT_TIME_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TIME_STRING_NEGATIVE_POWER_LENGTH*/), \
651 + max( (sizeof(QRT_TIME_OVERFLOW) - 1), \
652 + (sizeof(QRT_STRING_OVERFLOW) - 1) ) )
654 +#define QRT_TOTAL_STRING_LENGTH \
655 + max( (QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TOTAL_STRING_NEGATIVE_POWER_LENGTH*/), \
656 + max( (sizeof(QRT_TIME_OVERFLOW) - 1), \
657 + (sizeof(QRT_STRING_OVERFLOW) - 1) ) )
659 +extern ST_SCHEMA_TABLE query_response_time_table;
661 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
662 +extern void query_response_time_init ();
663 +extern void query_response_time_free ();
664 +extern void query_response_time_flush ();
665 +extern void query_response_time_collect(ulonglong query_time);
666 +extern int query_response_time_fill (THD* thd, TABLE_LIST *tables, COND *cond);
667 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
669 +#endif // QUERY_RESPONSE_TIME_H
670 diff -ruN a/sql/set_var.cc b/sql/set_var.cc
671 --- a/sql/set_var.cc 2010-11-01 08:43:57.000000000 +0000
672 +++ b/sql/set_var.cc 2010-11-01 08:52:40.000000000 +0000
673 @@ -1017,6 +1017,14 @@
674 static sys_var_use_global_long_query_time sys_use_global_long_query_time;
675 static sys_var_bool_ptr sys_slow_query_log_microseconds_timestamp(&vars, "slow_query_log_microseconds_timestamp",
676 &opt_slow_query_log_microseconds_timestamp);
677 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
678 +static sys_var_bool_ptr sys_enable_query_response_time_stats(&vars, "enable_query_response_time_stats",
679 + &opt_enable_query_response_time_stats);
680 +static sys_var_long_ptr sys_query_response_time_range_base(&vars, "query_response_time_range_base",
681 + &opt_query_response_time_range_base);
682 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
683 +static sys_var_have_variable sys_have_response_time_distribution(&vars, "have_response_time_distribution",
684 + &have_response_time_distribution);
685 /* Synonym of "slow_query_log" for consistency with SHOW VARIABLES output */
686 static sys_var_log_state sys_var_log_slow(&vars, "log_slow_queries",
687 &opt_slow_log, QUERY_LOG_SLOW);
688 diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc
689 --- a/sql/sql_parse.cc 2010-11-01 08:43:57.000000000 +0000
690 +++ b/sql/sql_parse.cc 2010-11-01 08:52:40.000000000 +0000
693 #include "sql_trigger.h"
694 #include "debug_sync.h"
695 +#include "query_response_time.h"
698 @defgroup Runtime_Environment Runtime Environment
699 @@ -1764,23 +1765,37 @@
700 Do not log administrative statements unless the appropriate option is
703 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
704 + if (opt_enable_query_response_time_stats || thd->enable_slow_log)
705 +#else /* HAVE_RESPONSE_TIME_DISTRIBUTION */
706 if (thd->enable_slow_log)
707 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
709 - ulonglong end_utime_of_query= thd->current_utime();
710 - thd_proc_info(thd, "logging slow query");
712 - if (((end_utime_of_query - thd->utime_after_lock) >
713 - thd->variables.long_query_time ||
714 - ((thd->server_status &
715 - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
716 - opt_log_queries_not_using_indexes &&
717 - !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) &&
718 - thd->examined_row_count >= thd->variables.min_examined_row_limit)
719 + ulonglong end_utime_of_query = thd->current_utime();
720 + ulonglong query_execution_time = end_utime_of_query - thd->utime_after_lock;
721 + #ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
722 + if(opt_enable_query_response_time_stats)
724 + query_response_time_collect(query_execution_time);
726 + #endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
727 + if (thd->enable_slow_log)
729 thd_proc_info(thd, "logging slow query");
730 - thd->status_var.long_query_count++;
731 - slow_log_print(thd, thd->query(), thd->query_length(),
732 - end_utime_of_query);
734 + if ((query_execution_time >
735 + thd->variables.long_query_time ||
736 + ((thd->server_status &
737 + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
738 + opt_log_queries_not_using_indexes &&
739 + !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) &&
740 + thd->examined_row_count >= thd->variables.min_examined_row_limit)
742 + thd_proc_info(thd, "logging slow query");
743 + thd->status_var.long_query_count++;
744 + slow_log_print(thd, thd->query(), thd->query_length(),
745 + end_utime_of_query);
750 @@ -1905,6 +1920,7 @@
754 + case SCH_QUERY_RESPONSE_TIME:
755 case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
756 case SCH_USER_PRIVILEGES:
757 case SCH_SCHEMA_PRIVILEGES:
758 @@ -7265,6 +7281,12 @@
759 init_global_index_stats();
760 pthread_mutex_unlock(&LOCK_global_index_stats);
762 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
763 + if (options & REFRESH_QUERY_RESPONSE_TIME)
765 + query_response_time_flush();
767 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
768 if (options & (REFRESH_USER_STATS | REFRESH_CLIENT_STATS | REFRESH_THREAD_STATS))
770 pthread_mutex_lock(&LOCK_global_user_client_stats);
771 diff -ruN a/sql/sql_show.cc b/sql/sql_show.cc
772 --- a/sql/sql_show.cc 2010-11-01 08:43:53.000000000 +0000
773 +++ b/sql/sql_show.cc 2010-11-01 08:52:40.000000000 +0000
775 #include "event_data_objects.h"
778 +#include "query_response_time.h"
779 #include "debug_sync.h"
781 #define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
782 @@ -7490,6 +7491,13 @@
786 +ST_FIELD_INFO query_response_time_fields_info[] =
788 + {"time", QRT_TIME_STRING_LENGTH, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE },
789 + {"count", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, MY_I_S_UNSIGNED, "", SKIP_OPEN_TABLE },
790 + {"total", QRT_TIME_STRING_LENGTH, MYSQL_TYPE_STRING, 0, 0, "", SKIP_OPEN_TABLE },
791 + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE }
793 ST_SCHEMA_TABLE schema_tables[]=
795 {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
796 @@ -7544,6 +7552,13 @@
797 1, 9, 0, OPEN_TABLE_ONLY},
798 {"ROUTINES", proc_fields_info, create_schema_table,
799 fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
800 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
801 + {"QUERY_RESPONSE_TIME", query_response_time_fields_info, create_schema_table,
802 + query_response_time_fill, make_old_format, 0, -1, -1, 0, 0},
803 +#else /* HAVE_RESPONSE_TIME_DISTRIBUTION */
804 + {"QUERY_RESPONSE_TIME", query_response_time_fields_info, create_schema_table,
805 + 0, make_old_format, 0, -1, -1, 0, 0},
806 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
807 {"SCHEMATA", schema_fields_info, create_schema_table,
808 fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
809 {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
810 diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy
811 --- a/sql/sql_yacc.yy 2010-11-01 08:43:53.000000000 +0000
812 +++ b/sql/sql_yacc.yy 2010-11-01 08:52:40.000000000 +0000
813 @@ -1079,6 +1079,7 @@
817 +%token QUERY_RESPONSE_TIME_SYM
819 %token RANGE_SYM /* SQL-2003-R */
820 %token READS_SYM /* SQL-2003-R */
821 @@ -10396,6 +10397,15 @@
822 if (prepare_schema_table(YYTHD, lex, 0, SCH_INDEX_STATS))
825 + | QUERY_RESPONSE_TIME_SYM wild_and_where
827 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
829 + lex->sql_command= SQLCOM_SELECT;
830 + if (prepare_schema_table(YYTHD, lex, 0, SCH_QUERY_RESPONSE_TIME))
832 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
834 | CREATE PROCEDURE sp_name
837 @@ -10616,6 +10626,12 @@
838 { Lex->type|= REFRESH_TABLE_STATS; }
840 { Lex->type|= REFRESH_INDEX_STATS; }
841 + | QUERY_RESPONSE_TIME_SYM
843 +#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
844 + Lex->type|= REFRESH_QUERY_RESPONSE_TIME;
845 +#endif /* HAVE_RESPONSE_TIME_DISTRIBUTION */
848 { Lex->type|= REFRESH_MASTER; }
850 @@ -11895,6 +11911,7 @@
854 + | QUERY_RESPONSE_TIME_SYM {}
858 diff -ruN a/sql/table.h b/sql/table.h
859 --- a/sql/table.h 2010-11-01 08:43:53.000000000 +0000
860 +++ b/sql/table.h 2010-11-01 08:52:40.000000000 +0000
863 SCH_REFERENTIAL_CONSTRAINTS,
865 + SCH_QUERY_RESPONSE_TIME,
867 SCH_SCHEMA_PRIVILEGES,
869 diff -ruN a/configure.in b/configure.in
870 --- a/configure.in 2010-12-07 19:19:42.000000000 +0300
871 +++ b/configure.in 2010-12-07 19:21:39.000000000 +0300
872 @@ -2687,7 +2687,16 @@
873 AC_SUBST(readline_link)
874 AC_SUBST(readline_h_ln_cmd)
876 +AC_ARG_WITH(response_time_distribution,
877 + AC_HELP_STRING([--without-response_time_distribution],[Disable response_time_distribution feature.]),
878 + [with_response_time_distribution=$withval],
879 + [with_response_time_distribution=yes]
882 +if test "$with_response_time_distribution" = "yes"
884 + AC_DEFINE([HAVE_RESPONSE_TIME_DISTRIBUTION], [1], [If we want to have response_time_distribution])
887 # Include man pages, if desired, adapted to the configured parts.
888 if test X"$with_man" = Xyes