1 /* Copyright (C) 2014 Percona and Sergey Vojtovich
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15
16 #include "mysql_version.h"
17 #include "my_global.h"
18 #include "mysql_com.h"
19 #include "rpl_tblmap.h"
20 #include "table.h"
21 #include "field.h"
22 #include "sql_show.h"
23 #include "query_response_time.h"
24
25 #define TIME_STRING_POSITIVE_POWER_LENGTH QRT_TIME_STRING_POSITIVE_POWER_LENGTH
26 #define TIME_STRING_NEGATIVE_POWER_LENGTH 6
27 #define TOTAL_STRING_POSITIVE_POWER_LENGTH QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH
28 #define TOTAL_STRING_NEGATIVE_POWER_LENGTH 6
29 #define MINIMUM_BASE 2
30 #define MAXIMUM_BASE QRT_MAXIMUM_BASE
31 #define POSITIVE_POWER_FILLER QRT_POSITIVE_POWER_FILLER
32 #define NEGATIVE_POWER_FILLER QRT_NEGATIVE_POWER_FILLER
33 #define TIME_OVERFLOW QRT_TIME_OVERFLOW
34 #define DEFAULT_BASE QRT_DEFAULT_BASE
35
36 #define do_xstr(s) do_str(s)
37 #define do_str(s) #s
38 #define do_format(filler,width) "%" filler width "lld"
39 /*
40 Format strings for snprintf. Generate from:
41 POSITIVE_POWER_FILLER and TIME_STRING_POSITIVE_POWER_LENGTH
42 NEFATIVE_POWER_FILLER and TIME_STRING_NEGATIVE_POWER_LENGTH
43 */
44 #define TIME_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TIME_STRING_POSITIVE_POWER_LENGTH))
45 #define TIME_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TIME_STRING_NEGATIVE_POWER_LENGTH))
46 #define TIME_STRING_FORMAT TIME_STRING_POSITIVE_POWER_FORMAT "." TIME_STRING_NEGATIVE_POWER_FORMAT
47
48 #define TOTAL_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TOTAL_STRING_POSITIVE_POWER_LENGTH))
49 #define TOTAL_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TOTAL_STRING_NEGATIVE_POWER_LENGTH))
50 #define TOTAL_STRING_FORMAT TOTAL_STRING_POSITIVE_POWER_FORMAT "." TOTAL_STRING_NEGATIVE_POWER_FORMAT
51
52 #define TIME_STRING_LENGTH QRT_TIME_STRING_LENGTH
53 #define TIME_STRING_BUFFER_LENGTH (TIME_STRING_LENGTH + 1 /* '\0' */)
54
55 #define TOTAL_STRING_LENGTH QRT_TOTAL_STRING_LENGTH
56 #define TOTAL_STRING_BUFFER_LENGTH (TOTAL_STRING_LENGTH + 1 /* '\0' */)
57
58 /*
59 Calculate length of "log linear"
60 1)
61 (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) < (MINIMUM_BASE ^ (result + 1))
62
63 2)
64 (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH)
65 and
66 (MINIMUM_BASE ^ (result + 1)) > (10 ^ STRING_POWER_LENGTH)
67
68 3)
69 result <= LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
70 result + 1 > LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
71
72 4) STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) - 1 < result <= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
73
74 MINIMUM_BASE= 2 always, LOG(MINIMUM_BASE,10)= 3.3219280948873626, result= (int)3.3219280948873626 * STRING_POWER_LENGTH
75
76 Last counter always use for time overflow
77 */
78 #define POSITIVE_POWER_COUNT ((int)(332192809ULL * TIME_STRING_POSITIVE_POWER_LENGTH / 100000000ULL))
79 #define NEGATIVE_POWER_COUNT ((int)(332192809ULL * TIME_STRING_NEGATIVE_POWER_LENGTH / 100000000ULL))
80 #define OVERALL_POWER_COUNT (NEGATIVE_POWER_COUNT + 1 + POSITIVE_POWER_COUNT)
81
82 #define MILLION ((unsigned long)1000 * 1000)
83
84 namespace query_response_time
85 {
86
87 class utility
88 {
89 public:
utility()90 utility() : m_base(0)
91 {
92 m_max_dec_value= MILLION;
93 for(int i= 0; TIME_STRING_POSITIVE_POWER_LENGTH > i; ++i)
94 m_max_dec_value *= 10;
95 setup(DEFAULT_BASE);
96 }
97 public:
base() const98 uint base() const { return m_base; }
negative_count() const99 uint negative_count() const { return m_negative_count; }
positive_count() const100 uint positive_count() const { return m_positive_count; }
bound_count() const101 uint bound_count() const { return m_bound_count; }
max_dec_value() const102 ulonglong max_dec_value() const { return m_max_dec_value; }
bound(uint index) const103 ulonglong bound(uint index) const { return m_bound[ index ]; }
104 public:
setup(uint base)105 void setup(uint base)
106 {
107 if(base != m_base)
108 {
109 m_base= base;
110
111 const ulonglong million= 1000 * 1000;
112 ulonglong value= million;
113 m_negative_count= 0;
114 while(value > 0)
115 {
116 m_negative_count += 1;
117 value /= m_base;
118 }
119 m_negative_count -= 1;
120
121 value= million;
122 m_positive_count= 0;
123 while(value < m_max_dec_value)
124 {
125 m_positive_count += 1;
126 value *= m_base;
127 }
128 m_bound_count= m_negative_count + m_positive_count;
129
130 value= million;
131 for(uint i= 0; i < m_negative_count; ++i)
132 {
133 value /= m_base;
134 m_bound[m_negative_count - i - 1]= value;
135 }
136 value= million;
137 for(uint i= 0; i < m_positive_count; ++i)
138 {
139 m_bound[m_negative_count + i]= value;
140 value *= m_base;
141 }
142 }
143 }
144 private:
145 uint m_base;
146 uint m_negative_count;
147 uint m_positive_count;
148 uint m_bound_count;
149 ulonglong m_max_dec_value; /* for TIME_STRING_POSITIVE_POWER_LENGTH=7 is 10000000 */
150 ulonglong m_bound[OVERALL_POWER_COUNT];
151 };
152
153 static
print_time(char * buffer,std::size_t buffer_size,const char * format,uint64 value)154 void print_time(char* buffer, std::size_t buffer_size, const char* format,
155 uint64 value)
156 {
157 ulonglong second= (value / MILLION);
158 ulonglong microsecond= (value % MILLION);
159 my_snprintf(buffer, buffer_size, format, second, microsecond);
160 }
161
162 class time_collector
163 {
164 public:
time_collector(utility & u)165 time_collector(utility& u) : m_utility(&u)
166 {
167 }
count(QUERY_TYPE type,uint index)168 uint32 count(QUERY_TYPE type, uint index)
169 {
170 return my_atomic_load32((int32*)&m_count[type][index]);
171 }
total(QUERY_TYPE type,uint index)172 uint64 total(QUERY_TYPE type, uint index)
173 {
174 return my_atomic_load64((int64*)&m_total[type][index]);
175 }
176 public:
flush()177 void flush()
178 {
179 memset((void*)&m_count,0,sizeof(m_count));
180 memset((void*)&m_total,0,sizeof(m_total));
181 }
collect(QUERY_TYPE type,uint64 time)182 void collect(QUERY_TYPE type, uint64 time)
183 {
184 int i= 0;
185 for(int count= m_utility->bound_count(); count > i; ++i)
186 {
187 if(m_utility->bound(i) > time)
188 {
189 my_atomic_add32((int32*)(&m_count[0][i]), 1);
190 my_atomic_add64((int64*)(&m_total[0][i]), time);
191 my_atomic_add32((int32*)(&m_count[type][i]), 1);
192 my_atomic_add64((int64*)(&m_total[type][i]), time);
193 break;
194 }
195 }
196 }
197 private:
198 utility* m_utility;
199 /*
200 The first row is for overall statistics,
201 the second row is for 'read' queries,
202 the third row is for 'write' queries.
203 */
204 uint32 m_count[3][OVERALL_POWER_COUNT + 1];
205 uint64 m_total[3][OVERALL_POWER_COUNT + 1];
206 };
207
208 class collector
209 {
210 public:
collector()211 collector() : m_time(m_utility)
212 {
213 m_utility.setup(DEFAULT_BASE);
214 m_time.flush();
215 }
216 public:
flush()217 void flush()
218 {
219 m_utility.setup(opt_query_response_time_range_base);
220 m_time.flush();
221 }
fill(QUERY_TYPE type,THD * thd,TABLE_LIST * tables,COND * cond)222 int fill(QUERY_TYPE type,
223 THD* thd,
224 TABLE_LIST *tables, COND *cond)
225 {
226 DBUG_ENTER("fill_schema_query_response_time");
227 TABLE *table= static_cast<TABLE*>(tables->table);
228 Field **fields= table->field;
229 for(uint i= 0, count= bound_count() + 1 /* with overflow */; count > i; ++i)
230 {
231 char time[TIME_STRING_BUFFER_LENGTH];
232 char total[TOTAL_STRING_BUFFER_LENGTH];
233 if(i == bound_count())
234 {
235 assert(sizeof(TIME_OVERFLOW) <= TIME_STRING_BUFFER_LENGTH);
236 assert(sizeof(TIME_OVERFLOW) <= TOTAL_STRING_BUFFER_LENGTH);
237 memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
238 memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
239 }
240 else
241 {
242 print_time(time, sizeof(time), TIME_STRING_FORMAT, this->bound(i));
243 print_time(total, sizeof(total), TOTAL_STRING_FORMAT, this->total(type, i));
244 }
245 fields[0]->store(time,strlen(time),system_charset_info);
246 fields[1]->store(this->count(type, i));
247 fields[2]->store(total,strlen(total),system_charset_info);
248 if (schema_table_store_record(thd, table))
249 {
250 DBUG_RETURN(1);
251 }
252 }
253 DBUG_RETURN(0);
254 }
collect(QUERY_TYPE type,ulonglong time)255 void collect(QUERY_TYPE type, ulonglong time)
256 {
257 m_time.collect(type, time);
258 }
bound_count() const259 uint bound_count() const
260 {
261 return m_utility.bound_count();
262 }
bound(uint index)263 ulonglong bound(uint index)
264 {
265 return m_utility.bound(index);
266 }
count(QUERY_TYPE type,uint index)267 ulonglong count(QUERY_TYPE type, uint index)
268 {
269 return m_time.count(type, index);
270 }
total(QUERY_TYPE type,uint index)271 ulonglong total(QUERY_TYPE type, uint index)
272 {
273 return m_time.total(type, index);
274 }
275 private:
276 utility m_utility;
277 time_collector m_time;
278 };
279
280 static collector g_collector;
281
282 } // namespace query_response_time
283
query_response_time_init()284 void query_response_time_init()
285 {
286 query_response_time_flush();
287 }
288
query_response_time_free()289 void query_response_time_free()
290 {
291 query_response_time::g_collector.flush();
292 }
293
query_response_time_flush()294 void query_response_time_flush()
295 {
296 query_response_time::g_collector.flush();
297 }
298
query_response_time_collect(QUERY_TYPE type,ulonglong query_time)299 void query_response_time_collect(QUERY_TYPE type,
300 ulonglong query_time)
301 {
302 query_response_time::g_collector.collect(type, query_time);
303 }
304
query_response_time_fill(THD * thd,TABLE_LIST * tables,COND * cond)305 int query_response_time_fill(THD* thd, TABLE_LIST *tables, COND *cond)
306 {
307 return query_response_time::g_collector.fill(ANY, thd, tables, cond);
308 }
309
query_response_time_fill_ro(THD * thd,TABLE_LIST * tables,COND * cond)310 int query_response_time_fill_ro(THD* thd, TABLE_LIST *tables, COND *cond)
311 {
312 return query_response_time::g_collector.fill(READ, thd, tables, cond);
313 }
314
query_response_time_fill_rw(THD * thd,TABLE_LIST * tables,COND * cond)315 int query_response_time_fill_rw(THD* thd, TABLE_LIST *tables, COND *cond)
316 {
317 return query_response_time::g_collector.fill(WRITE, thd, tables, cond);
318 }
319