1/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
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 Foundation,
14 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15
16/**
17 @file storage/perfschema/table_events_stages.cc
18 Table EVENTS_STAGES_xxx (implementation).
19*/
20
21#include "my_global.h"
22#include "my_pthread.h"
23#include "table_events_stages.h"
24#include "pfs_instr_class.h"
25#include "pfs_instr.h"
26#include "pfs_events_stages.h"
27#include "pfs_timer.h"
28
29THR_LOCK table_events_stages_current::m_table_lock;
30
31PFS_engine_table_share
32table_events_stages_current::m_share=
33{
34 { C_STRING_WITH_LEN("events_stages_current") },
35 &pfs_truncatable_acl,
36 &table_events_stages_current::create,
37 NULL, /* write_row */
38 &table_events_stages_current::delete_all_rows,
39 NULL, /* get_row_count */
40 1000, /* records */
41 sizeof(PFS_simple_index), /* ref length */
42 &m_table_lock,
43 { C_STRING_WITH_LEN("CREATE TABLE events_stages_current("
44 "THREAD_ID BIGINT unsigned not null,"
45 "EVENT_ID BIGINT unsigned not null,"
46 "END_EVENT_ID BIGINT unsigned,"
47 "EVENT_NAME VARCHAR(128) not null,"
48 "SOURCE VARCHAR(64),"
49 "TIMER_START BIGINT unsigned,"
50 "TIMER_END BIGINT unsigned,"
51 "TIMER_WAIT BIGINT unsigned,"
52 "NESTING_EVENT_ID BIGINT unsigned,"
53 "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
54};
55
56THR_LOCK table_events_stages_history::m_table_lock;
57
58PFS_engine_table_share
59table_events_stages_history::m_share=
60{
61 { C_STRING_WITH_LEN("events_stages_history") },
62 &pfs_truncatable_acl,
63 &table_events_stages_history::create,
64 NULL, /* write_row */
65 &table_events_stages_history::delete_all_rows,
66 NULL, /* get_row_count */
67 1000, /* records */
68 sizeof(pos_events_stages_history), /* ref length */
69 &m_table_lock,
70 { C_STRING_WITH_LEN("CREATE TABLE events_stages_history("
71 "THREAD_ID BIGINT unsigned not null,"
72 "EVENT_ID BIGINT unsigned not null,"
73 "END_EVENT_ID BIGINT unsigned,"
74 "EVENT_NAME VARCHAR(128) not null,"
75 "SOURCE VARCHAR(64),"
76 "TIMER_START BIGINT unsigned,"
77 "TIMER_END BIGINT unsigned,"
78 "TIMER_WAIT BIGINT unsigned,"
79 "NESTING_EVENT_ID BIGINT unsigned,"
80 "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
81};
82
83THR_LOCK table_events_stages_history_long::m_table_lock;
84
85PFS_engine_table_share
86table_events_stages_history_long::m_share=
87{
88 { C_STRING_WITH_LEN("events_stages_history_long") },
89 &pfs_truncatable_acl,
90 &table_events_stages_history_long::create,
91 NULL, /* write_row */
92 &table_events_stages_history_long::delete_all_rows,
93 NULL, /* get_row_count */
94 10000, /* records */
95 sizeof(PFS_simple_index), /* ref length */
96 &m_table_lock,
97 { C_STRING_WITH_LEN("CREATE TABLE events_stages_history_long("
98 "THREAD_ID BIGINT unsigned not null,"
99 "EVENT_ID BIGINT unsigned not null,"
100 "END_EVENT_ID BIGINT unsigned,"
101 "EVENT_NAME VARCHAR(128) not null,"
102 "SOURCE VARCHAR(64),"
103 "TIMER_START BIGINT unsigned,"
104 "TIMER_END BIGINT unsigned,"
105 "TIMER_WAIT BIGINT unsigned,"
106 "NESTING_EVENT_ID BIGINT unsigned,"
107 "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
108};
109
110table_events_stages_common::table_events_stages_common
111(const PFS_engine_table_share *share, void *pos)
112 : PFS_engine_table(share, pos),
113 m_row_exists(false)
114{}
115
116/**
117 Build a row.
118 @param stage the stage the cursor is reading
119*/
120void table_events_stages_common::make_row(PFS_events_stages *stage)
121{
122 const char *base;
123 const char *safe_source_file;
124 ulonglong timer_end;
125
126 m_row_exists= false;
127
128 PFS_stage_class *unsafe= (PFS_stage_class*) stage->m_class;
129 PFS_stage_class *klass= sanitize_stage_class(unsafe);
130 if (unlikely(klass == NULL))
131 return;
132
133 m_row.m_thread_internal_id= stage->m_thread_internal_id;
134 m_row.m_event_id= stage->m_event_id;
135 m_row.m_end_event_id= stage->m_end_event_id;
136 m_row.m_nesting_event_id= stage->m_nesting_event_id;
137 m_row.m_nesting_event_type= stage->m_nesting_event_type;
138
139 if (m_row.m_end_event_id == 0)
140 {
141 timer_end= get_timer_raw_value(stage_timer);
142 }
143 else
144 {
145 timer_end= stage->m_timer_end;
146 }
147
148 m_normalizer->to_pico(stage->m_timer_start, timer_end,
149 & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
150
151 m_row.m_name= klass->m_name;
152 m_row.m_name_length= klass->m_name_length;
153
154 safe_source_file= stage->m_source_file;
155 if (unlikely(safe_source_file == NULL))
156 return;
157
158 base= base_name(safe_source_file);
159 m_row.m_source_length= (uint)my_snprintf(m_row.m_source, sizeof(m_row.m_source),
160 "%s:%d", base, stage->m_source_line);
161 if (m_row.m_source_length > sizeof(m_row.m_source))
162 m_row.m_source_length= sizeof(m_row.m_source);
163
164 m_row_exists= true;
165 return;
166}
167
168int table_events_stages_common::read_row_values(TABLE *table,
169 unsigned char *buf,
170 Field **fields,
171 bool read_all)
172{
173 Field *f;
174
175 if (unlikely(! m_row_exists))
176 return HA_ERR_RECORD_DELETED;
177
178 /* Set the null bits */
179 DBUG_ASSERT(table->s->null_bytes == 1);
180 buf[0]= 0;
181
182 for (; (f= *fields) ; fields++)
183 {
184 if (read_all || bitmap_is_set(table->read_set, f->field_index))
185 {
186 switch(f->field_index)
187 {
188 case 0: /* THREAD_ID */
189 set_field_ulonglong(f, m_row.m_thread_internal_id);
190 break;
191 case 1: /* EVENT_ID */
192 set_field_ulonglong(f, m_row.m_event_id);
193 break;
194 case 2: /* END_EVENT_ID */
195 if (m_row.m_end_event_id > 0)
196 set_field_ulonglong(f, m_row.m_end_event_id - 1);
197 else
198 f->set_null();
199 break;
200 case 3: /* EVENT_NAME */
201 set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
202 break;
203 case 4: /* SOURCE */
204 set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length);
205 break;
206 case 5: /* TIMER_START */
207 if (m_row.m_timer_start != 0)
208 set_field_ulonglong(f, m_row.m_timer_start);
209 else
210 f->set_null();
211 break;
212 case 6: /* TIMER_END */
213 if (m_row.m_timer_end != 0)
214 set_field_ulonglong(f, m_row.m_timer_end);
215 else
216 f->set_null();
217 break;
218 case 7: /* TIMER_WAIT */
219 if (m_row.m_timer_wait != 0)
220 set_field_ulonglong(f, m_row.m_timer_wait);
221 else
222 f->set_null();
223 break;
224 case 8: /* NESTING_EVENT_ID */
225 if (m_row.m_nesting_event_id != 0)
226 set_field_ulonglong(f, m_row.m_nesting_event_id);
227 else
228 f->set_null();
229 break;
230 case 9: /* NESTING_EVENT_TYPE */
231 if (m_row.m_nesting_event_id != 0)
232 set_field_enum(f, m_row.m_nesting_event_type);
233 else
234 f->set_null();
235 break;
236 default:
237 DBUG_ASSERT(false);
238 }
239 }
240 }
241 return 0;
242}
243
244PFS_engine_table* table_events_stages_current::create(void)
245{
246 return new table_events_stages_current();
247}
248
249table_events_stages_current::table_events_stages_current()
250 : table_events_stages_common(&m_share, &m_pos),
251 m_pos(0), m_next_pos(0)
252{}
253
254void table_events_stages_current::reset_position(void)
255{
256 m_pos.m_index= 0;
257 m_next_pos.m_index= 0;
258}
259
260int table_events_stages_current::rnd_init(bool scan)
261{
262 m_normalizer= time_normalizer::get(stage_timer);
263 return 0;
264}
265
266int table_events_stages_current::rnd_next(void)
267{
268 PFS_thread *pfs_thread;
269 PFS_events_stages *stage;
270
271 for (m_pos.set_at(&m_next_pos);
272 m_pos.m_index < thread_max;
273 m_pos.next())
274 {
275 pfs_thread= &thread_array[m_pos.m_index];
276
277 if (! pfs_thread->m_lock.is_populated())
278 {
279 /* This thread does not exist */
280 continue;
281 }
282
283 stage= &pfs_thread->m_stage_current;
284
285 make_row(stage);
286 m_next_pos.set_after(&m_pos);
287 return 0;
288 }
289
290 return HA_ERR_END_OF_FILE;
291}
292
293int table_events_stages_current::rnd_pos(const void *pos)
294{
295 PFS_thread *pfs_thread;
296 PFS_events_stages *stage;
297
298 set_position(pos);
299 DBUG_ASSERT(m_pos.m_index < thread_max);
300 pfs_thread= &thread_array[m_pos.m_index];
301
302 if (! pfs_thread->m_lock.is_populated())
303 return HA_ERR_RECORD_DELETED;
304
305 stage= &pfs_thread->m_stage_current;
306 make_row(stage);
307 return 0;
308}
309
310int table_events_stages_current::delete_all_rows(void)
311{
312 reset_events_stages_current();
313 return 0;
314}
315
316PFS_engine_table* table_events_stages_history::create(void)
317{
318 return new table_events_stages_history();
319}
320
321table_events_stages_history::table_events_stages_history()
322 : table_events_stages_common(&m_share, &m_pos),
323 m_pos(), m_next_pos()
324{}
325
326void table_events_stages_history::reset_position(void)
327{
328 m_pos.reset();
329 m_next_pos.reset();
330}
331
332int table_events_stages_history::rnd_init(bool scan)
333{
334 m_normalizer= time_normalizer::get(stage_timer);
335 return 0;
336}
337
338int table_events_stages_history::rnd_next(void)
339{
340 PFS_thread *pfs_thread;
341 PFS_events_stages *stage;
342
343 if (events_stages_history_per_thread == 0)
344 return HA_ERR_END_OF_FILE;
345
346 for (m_pos.set_at(&m_next_pos);
347 m_pos.m_index_1 < thread_max;
348 m_pos.next_thread())
349 {
350 pfs_thread= &thread_array[m_pos.m_index_1];
351
352 if (! pfs_thread->m_lock.is_populated())
353 {
354 /* This thread does not exist */
355 continue;
356 }
357
358 if (m_pos.m_index_2 >= events_stages_history_per_thread)
359 {
360 /* This thread does not have more (full) history */
361 continue;
362 }
363
364 if ( ! pfs_thread->m_stages_history_full &&
365 (m_pos.m_index_2 >= pfs_thread->m_stages_history_index))
366 {
367 /* This thread does not have more (not full) history */
368 continue;
369 }
370
371 stage= &pfs_thread->m_stages_history[m_pos.m_index_2];
372
373 if (stage->m_class != NULL)
374 {
375 make_row(stage);
376 /* Next iteration, look for the next history in this thread */
377 m_next_pos.set_after(&m_pos);
378 return 0;
379 }
380 }
381
382 return HA_ERR_END_OF_FILE;
383}
384
385int table_events_stages_history::rnd_pos(const void *pos)
386{
387 PFS_thread *pfs_thread;
388 PFS_events_stages *stage;
389
390 DBUG_ASSERT(events_stages_history_per_thread != 0);
391 set_position(pos);
392 DBUG_ASSERT(m_pos.m_index_1 < thread_max);
393 pfs_thread= &thread_array[m_pos.m_index_1];
394
395 if (! pfs_thread->m_lock.is_populated())
396 return HA_ERR_RECORD_DELETED;
397
398 DBUG_ASSERT(m_pos.m_index_2 < events_stages_history_per_thread);
399
400 if ( ! pfs_thread->m_stages_history_full &&
401 (m_pos.m_index_2 >= pfs_thread->m_stages_history_index))
402 return HA_ERR_RECORD_DELETED;
403
404 stage= &pfs_thread->m_stages_history[m_pos.m_index_2];
405
406 if (stage->m_class == NULL)
407 return HA_ERR_RECORD_DELETED;
408
409 make_row(stage);
410 return 0;
411}
412
413int table_events_stages_history::delete_all_rows(void)
414{
415 reset_events_stages_history();
416 return 0;
417}
418
419PFS_engine_table* table_events_stages_history_long::create(void)
420{
421 return new table_events_stages_history_long();
422}
423
424table_events_stages_history_long::table_events_stages_history_long()
425 : table_events_stages_common(&m_share, &m_pos),
426 m_pos(0), m_next_pos(0)
427{}
428
429void table_events_stages_history_long::reset_position(void)
430{
431 m_pos.m_index= 0;
432 m_next_pos.m_index= 0;
433}
434
435int table_events_stages_history_long::rnd_init(bool scan)
436{
437 m_normalizer= time_normalizer::get(stage_timer);
438 return 0;
439}
440
441int table_events_stages_history_long::rnd_next(void)
442{
443 PFS_events_stages *stage;
444 uint limit;
445
446 if (events_stages_history_long_size == 0)
447 return HA_ERR_END_OF_FILE;
448
449 if (events_stages_history_long_full)
450 limit= events_stages_history_long_size;
451 else
452 limit= events_stages_history_long_index % events_stages_history_long_size;
453
454 for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
455 {
456 stage= &events_stages_history_long_array[m_pos.m_index];
457
458 if (stage->m_class != NULL)
459 {
460 make_row(stage);
461 /* Next iteration, look for the next entry */
462 m_next_pos.set_after(&m_pos);
463 return 0;
464 }
465 }
466
467 return HA_ERR_END_OF_FILE;
468}
469
470int table_events_stages_history_long::rnd_pos(const void *pos)
471{
472 PFS_events_stages *stage;
473 uint limit;
474
475 if (events_stages_history_long_size == 0)
476 return HA_ERR_RECORD_DELETED;
477
478 set_position(pos);
479
480 if (events_stages_history_long_full)
481 limit= events_stages_history_long_size;
482 else
483 limit= events_stages_history_long_index % events_stages_history_long_size;
484
485 if (m_pos.m_index > limit)
486 return HA_ERR_RECORD_DELETED;
487
488 stage= &events_stages_history_long_array[m_pos.m_index];
489
490 if (stage->m_class == NULL)
491 return HA_ERR_RECORD_DELETED;
492
493 make_row(stage);
494 return 0;
495}
496
497int table_events_stages_history_long::delete_all_rows(void)
498{
499 reset_events_stages_history_long();
500 return 0;
501}
502
503