1 /* Copyright (c) 2008, 2010, 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_waits.cc
18 Table EVENTS_WAITS_xxx (implementation).
19 */
20
21 #include "my_global.h"
22 #include "my_pthread.h"
23 #include "table_events_waits.h"
24 #include "pfs_instr_class.h"
25 #include "pfs_instr.h"
26 #include "pfs_events_waits.h"
27
28 THR_LOCK table_events_waits_current::m_table_lock;
29
30 static const TABLE_FIELD_TYPE field_types[]=
31 {
32 {
33 { C_STRING_WITH_LEN("THREAD_ID") },
34 { C_STRING_WITH_LEN("int(11)") },
35 { NULL, 0}
36 },
37 {
38 { C_STRING_WITH_LEN("EVENT_ID") },
39 { C_STRING_WITH_LEN("bigint(20)") },
40 { NULL, 0}
41 },
42 {
43 { C_STRING_WITH_LEN("EVENT_NAME") },
44 { C_STRING_WITH_LEN("varchar(128)") },
45 { NULL, 0}
46 },
47 {
48 { C_STRING_WITH_LEN("SOURCE") },
49 { C_STRING_WITH_LEN("varchar(64)") },
50 { NULL, 0}
51 },
52 {
53 { C_STRING_WITH_LEN("TIMER_START") },
54 { C_STRING_WITH_LEN("bigint(20)") },
55 { NULL, 0}
56 },
57 {
58 { C_STRING_WITH_LEN("TIMER_END") },
59 { C_STRING_WITH_LEN("bigint(20)") },
60 { NULL, 0}
61 },
62 {
63 { C_STRING_WITH_LEN("TIMER_WAIT") },
64 { C_STRING_WITH_LEN("bigint(20)") },
65 { NULL, 0}
66 },
67 {
68 { C_STRING_WITH_LEN("SPINS") },
69 { C_STRING_WITH_LEN("int(10)") },
70 { NULL, 0}
71 },
72 {
73 { C_STRING_WITH_LEN("OBJECT_SCHEMA") },
74 { C_STRING_WITH_LEN("varchar(64)") },
75 { NULL, 0}
76 },
77 {
78 { C_STRING_WITH_LEN("OBJECT_NAME") },
79 { C_STRING_WITH_LEN("varchar(512)") },
80 { NULL, 0}
81 },
82 {
83 { C_STRING_WITH_LEN("OBJECT_TYPE") },
84 { C_STRING_WITH_LEN("varchar(64)") },
85 { NULL, 0}
86 },
87 {
88 { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
89 { C_STRING_WITH_LEN("bigint(20)") },
90 { NULL, 0}
91 },
92 {
93 { C_STRING_WITH_LEN("NESTING_EVENT_ID") },
94 { C_STRING_WITH_LEN("bigint(20)") },
95 { NULL, 0}
96 },
97 {
98 { C_STRING_WITH_LEN("OPERATION") },
99 { C_STRING_WITH_LEN("varchar(16)") },
100 { NULL, 0}
101 },
102 {
103 { C_STRING_WITH_LEN("NUMBER_OF_BYTES") },
104 { C_STRING_WITH_LEN("bigint(20)") },
105 { NULL, 0}
106 },
107 {
108 { C_STRING_WITH_LEN("FLAGS") },
109 { C_STRING_WITH_LEN("int(10)") },
110 { NULL, 0}
111 }
112 };
113
114 TABLE_FIELD_DEF
115 table_events_waits_current::m_field_def=
116 { 16, field_types };
117
118 PFS_engine_table_share
119 table_events_waits_current::m_share=
120 {
121 { C_STRING_WITH_LEN("events_waits_current") },
122 &pfs_truncatable_acl,
123 &table_events_waits_current::create,
124 NULL, /* write_row */
125 &table_events_waits_current::delete_all_rows,
126 1000, /* records */
127 sizeof(pos_events_waits_current), /* ref length */
128 &m_table_lock,
129 &m_field_def,
130 false /* checked */
131 };
132
133 THR_LOCK table_events_waits_history::m_table_lock;
134
135 PFS_engine_table_share
136 table_events_waits_history::m_share=
137 {
138 { C_STRING_WITH_LEN("events_waits_history") },
139 &pfs_truncatable_acl,
140 &table_events_waits_history::create,
141 NULL, /* write_row */
142 &table_events_waits_history::delete_all_rows,
143 1000, /* records */
144 sizeof(pos_events_waits_history), /* ref length */
145 &m_table_lock,
146 &table_events_waits_current::m_field_def,
147 false /* checked */
148 };
149
150 THR_LOCK table_events_waits_history_long::m_table_lock;
151
152 PFS_engine_table_share
153 table_events_waits_history_long::m_share=
154 {
155 { C_STRING_WITH_LEN("events_waits_history_long") },
156 &pfs_truncatable_acl,
157 &table_events_waits_history_long::create,
158 NULL, /* write_row */
159 &table_events_waits_history_long::delete_all_rows,
160 10000, /* records */
161 sizeof(PFS_simple_index), /* ref length */
162 &m_table_lock,
163 &table_events_waits_current::m_field_def,
164 false /* checked */
165 };
166
table_events_waits_common(const PFS_engine_table_share * share,void * pos)167 table_events_waits_common::table_events_waits_common
168 (const PFS_engine_table_share *share, void *pos)
169 : PFS_engine_table(share, pos),
170 m_row_exists(false)
171 {}
172
clear_object_columns()173 void table_events_waits_common::clear_object_columns()
174 {
175 m_row.m_object_type= NULL;
176 m_row.m_object_type_length= 0;
177 m_row.m_object_schema_length= 0;
178 m_row.m_object_name_length= 0;
179 }
180
181 /**
182 Build a row.
183 @param thread_own_wait True if the memory for the wait
184 is owned by pfs_thread
185 @param pfs_thread the thread the cursor is reading
186 @param wait the wait the cursor is reading
187 */
make_row(bool thread_own_wait,PFS_thread * pfs_thread,volatile PFS_events_waits * wait)188 void table_events_waits_common::make_row(bool thread_own_wait,
189 PFS_thread *pfs_thread,
190 volatile PFS_events_waits *wait)
191 {
192 pfs_lock lock;
193 PFS_thread *safe_thread;
194 PFS_instr_class *safe_class;
195 const char *base;
196 const char *safe_source_file;
197 const char *safe_table_schema_name;
198 const char *safe_table_object_name;
199 const char *safe_file_name;
200
201 m_row_exists= false;
202 safe_thread= sanitize_thread(pfs_thread);
203 if (unlikely(safe_thread == NULL))
204 return;
205
206 /* Protect this reader against a thread termination */
207 if (thread_own_wait)
208 safe_thread->m_lock.begin_optimistic_lock(&lock);
209
210 /*
211 Design choice:
212 We could have used a pfs_lock in PFS_events_waits here,
213 to protect the reader from concurrent event generation,
214 but this leads to too many pfs_lock atomic operations
215 each time an event is recorded:
216 - 1 dirty() + 1 allocated() per event start, for EVENTS_WAITS_CURRENT
217 - 1 dirty() + 1 allocated() per event end, for EVENTS_WAITS_CURRENT
218 - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY
219 - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY_LONG
220 or 8 atomics per recorded event.
221 The problem is that we record a *lot* of events ...
222
223 This code is prepared to accept *dirty* records,
224 and sanitizes all the data before returning a row.
225 */
226
227 m_row.m_thread_internal_id= safe_thread->m_thread_internal_id;
228 m_row.m_event_id= wait->m_event_id;
229 m_row.m_timer_state= wait->m_timer_state;
230 m_row.m_timer_start= wait->m_timer_start;
231 m_row.m_timer_end= wait->m_timer_end;
232 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
233
234 /*
235 PFS_events_waits::m_class needs to be sanitized,
236 for race conditions when this code:
237 - reads a new value in m_wait_class,
238 - reads an old value in m_class.
239 */
240 switch (wait->m_wait_class)
241 {
242 case WAIT_CLASS_MUTEX:
243 clear_object_columns();
244 safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class);
245 break;
246 case WAIT_CLASS_RWLOCK:
247 clear_object_columns();
248 safe_class= sanitize_rwlock_class((PFS_rwlock_class*) wait->m_class);
249 break;
250 case WAIT_CLASS_COND:
251 clear_object_columns();
252 safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class);
253 break;
254 case WAIT_CLASS_TABLE:
255 m_row.m_object_type= "TABLE";
256 m_row.m_object_type_length= 5;
257 m_row.m_object_schema_length= wait->m_schema_name_length;
258 safe_table_schema_name= sanitize_table_schema_name(wait->m_schema_name);
259 if (unlikely((m_row.m_object_schema_length == 0) ||
260 (m_row.m_object_schema_length > sizeof(m_row.m_object_schema)) ||
261 (safe_table_schema_name == NULL)))
262 return;
263 memcpy(m_row.m_object_schema, safe_table_schema_name, m_row.m_object_schema_length);
264 m_row.m_object_name_length= wait->m_object_name_length;
265 safe_table_object_name= sanitize_table_object_name(wait->m_object_name);
266 if (unlikely((m_row.m_object_name_length == 0) ||
267 (m_row.m_object_name_length > sizeof(m_row.m_object_name)) ||
268 (safe_table_object_name == NULL)))
269 return;
270 memcpy(m_row.m_object_name, safe_table_object_name, m_row.m_object_name_length);
271 safe_class= &global_table_class;
272 break;
273 case WAIT_CLASS_FILE:
274 m_row.m_object_type= "FILE";
275 m_row.m_object_type_length= 4;
276 m_row.m_object_schema_length= 0;
277 m_row.m_object_name_length= wait->m_object_name_length;
278 safe_file_name= sanitize_file_name(wait->m_object_name);
279 if (unlikely((m_row.m_object_name_length == 0) ||
280 (m_row.m_object_name_length > sizeof(m_row.m_object_name)) ||
281 (safe_file_name == NULL)))
282 return;
283 memcpy(m_row.m_object_name, safe_file_name, m_row.m_object_name_length);
284 safe_class= sanitize_file_class((PFS_file_class*) wait->m_class);
285 break;
286 case NO_WAIT_CLASS:
287 default:
288 return;
289 }
290 if (unlikely(safe_class == NULL))
291 return;
292 m_row.m_name= safe_class->m_name;
293 m_row.m_name_length= safe_class->m_name_length;
294
295 /*
296 We are assuming this pointer is sane,
297 since it comes from __FILE__.
298 */
299 safe_source_file= wait->m_source_file;
300 if (unlikely(safe_source_file == NULL))
301 return;
302
303 base= base_name(wait->m_source_file);
304 m_row.m_source_length= my_snprintf(m_row.m_source, sizeof(m_row.m_source),
305 "%s:%d", base, wait->m_source_line);
306 if (m_row.m_source_length > sizeof(m_row.m_source))
307 m_row.m_source_length= sizeof(m_row.m_source);
308 m_row.m_operation= wait->m_operation;
309 m_row.m_number_of_bytes= wait->m_number_of_bytes;
310 m_row.m_flags= 0;
311
312 if (thread_own_wait)
313 {
314 if (safe_thread->m_lock.end_optimistic_lock(&lock))
315 m_row_exists= true;
316 }
317 else
318 {
319 /*
320 For EVENTS_WAITS_HISTORY_LONG (thread_own_wait is false),
321 the wait record is always valid, because it is not stored
322 in memory owned by pfs_thread.
323 Even when the thread terminated, the record is mostly readable,
324 so this record is displayed.
325 */
326 m_row_exists= true;
327 }
328 }
329
330 /**
331 Operations names map, as displayed in the 'OPERATION' column.
332 Indexed by enum_operation_type - 1.
333 Note: enum_operation_type contains a more precise definition,
334 since more details are needed internally by the instrumentation.
335 Different similar operations (CLOSE vs STREAMCLOSE) are displayed
336 with the same name 'close'.
337 */
338 static const LEX_STRING operation_names_map[]=
339 {
340 /* Mutex operations */
341 { C_STRING_WITH_LEN("lock") },
342 { C_STRING_WITH_LEN("try_lock") },
343
344 /* RWLock operations */
345 { C_STRING_WITH_LEN("read_lock") },
346 { C_STRING_WITH_LEN("write_lock") },
347 { C_STRING_WITH_LEN("try_read_lock") },
348 { C_STRING_WITH_LEN("try_write_lock") },
349
350 /* Condition operations */
351 { C_STRING_WITH_LEN("wait") },
352 { C_STRING_WITH_LEN("timed_wait") },
353
354 /* File operations */
355 { C_STRING_WITH_LEN("create") },
356 { C_STRING_WITH_LEN("create") }, /* create tmp */
357 { C_STRING_WITH_LEN("open") },
358 { C_STRING_WITH_LEN("open") }, /* stream open */
359 { C_STRING_WITH_LEN("close") },
360 { C_STRING_WITH_LEN("close") }, /* stream close */
361 { C_STRING_WITH_LEN("read") },
362 { C_STRING_WITH_LEN("write") },
363 { C_STRING_WITH_LEN("seek") },
364 { C_STRING_WITH_LEN("tell") },
365 { C_STRING_WITH_LEN("flush") },
366 { C_STRING_WITH_LEN("stat") },
367 { C_STRING_WITH_LEN("stat") }, /* fstat */
368 { C_STRING_WITH_LEN("chsize") },
369 { C_STRING_WITH_LEN("delete") },
370 { C_STRING_WITH_LEN("rename") },
371 { C_STRING_WITH_LEN("sync") }
372 };
373
374
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)375 int table_events_waits_common::read_row_values(TABLE *table,
376 unsigned char *buf,
377 Field **fields,
378 bool read_all)
379 {
380 Field *f;
381 const LEX_STRING *operation;
382
383 compile_time_assert(COUNT_OPERATION_TYPE ==
384 array_elements(operation_names_map));
385
386 if (unlikely(! m_row_exists))
387 return HA_ERR_RECORD_DELETED;
388
389 /* Set the null bits */
390 DBUG_ASSERT(table->s->null_bytes == 2);
391 buf[0]= 0;
392 buf[1]= 0;
393
394 /*
395 Some columns are unreliable, because they are joined with other buffers,
396 which could have changed and been reused for something else.
397 These columns are:
398 - THREAD_ID (m_thread joins with PFS_thread),
399 - SCHEMA_NAME (m_schema_name joins with PFS_table_share)
400 - OBJECT_NAME (m_object_name joins with PFS_table_share)
401 */
402 for (; (f= *fields) ; fields++)
403 {
404 if (read_all || bitmap_is_set(table->read_set, f->field_index))
405 {
406 switch(f->field_index)
407 {
408 case 0: /* THREAD_ID */
409 set_field_ulong(f, m_row.m_thread_internal_id);
410 break;
411 case 1: /* EVENT_ID */
412 set_field_ulonglong(f, m_row.m_event_id);
413 break;
414 case 2: /* EVENT_NAME */
415 set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
416 break;
417 case 3: /* SOURCE */
418 set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length);
419 break;
420 case 4: /* TIMER_START */
421 if ((m_row.m_timer_state == TIMER_STATE_STARTED) ||
422 (m_row.m_timer_state == TIMER_STATE_TIMED))
423 set_field_ulonglong(f, m_row.m_timer_start);
424 else
425 f->set_null();
426 break;
427 case 5: /* TIMER_END */
428 if (m_row.m_timer_state == TIMER_STATE_TIMED)
429 set_field_ulonglong(f, m_row.m_timer_end);
430 else
431 f->set_null();
432 break;
433 case 6: /* TIMER_WAIT */
434 if (m_row.m_timer_state == TIMER_STATE_TIMED)
435 set_field_ulonglong(f, m_row.m_timer_end - m_row.m_timer_start);
436 else
437 f->set_null();
438 break;
439 case 7: /* SPINS */
440 f->set_null();
441 break;
442 case 8: /* OBJECT_SCHEMA */
443 if (m_row.m_object_schema_length > 0)
444 {
445 set_field_varchar_utf8(f, m_row.m_object_schema,
446 m_row.m_object_schema_length);
447 }
448 else
449 f->set_null();
450 break;
451 case 9: /* OBJECT_NAME */
452 if (m_row.m_object_name_length > 0)
453 {
454 set_field_varchar_utf8(f, m_row.m_object_name,
455 m_row.m_object_name_length);
456 }
457 else
458 f->set_null();
459 break;
460 case 10: /* OBJECT_TYPE */
461 if (m_row.m_object_type)
462 {
463 set_field_varchar_utf8(f, m_row.m_object_type,
464 m_row.m_object_type_length);
465 }
466 else
467 f->set_null();
468 break;
469 case 11: /* OBJECT_INSTANCE */
470 set_field_ulonglong(f, m_row.m_object_instance_addr);
471 break;
472 case 12: /* NESTING_EVENT_ID */
473 f->set_null();
474 break;
475 case 13: /* OPERATION */
476 operation= &operation_names_map[(int) m_row.m_operation - 1];
477 set_field_varchar_utf8(f, operation->str, operation->length);
478 break;
479 case 14: /* NUMBER_OF_BYTES */
480 if ((m_row.m_operation == OPERATION_TYPE_FILEREAD) ||
481 (m_row.m_operation == OPERATION_TYPE_FILEWRITE) ||
482 (m_row.m_operation == OPERATION_TYPE_FILECHSIZE))
483 set_field_ulonglong(f, m_row.m_number_of_bytes);
484 else
485 f->set_null();
486 break;
487 case 15: /* FLAGS */
488 set_field_ulong(f, m_row.m_flags);
489 break;
490 default:
491 DBUG_ASSERT(false);
492 }
493 }
494 }
495 return 0;
496 }
497
create(void)498 PFS_engine_table* table_events_waits_current::create(void)
499 {
500 return new table_events_waits_current();
501 }
502
table_events_waits_current()503 table_events_waits_current::table_events_waits_current()
504 : table_events_waits_common(&m_share, &m_pos),
505 m_pos(), m_next_pos()
506 {}
507
reset_position(void)508 void table_events_waits_current::reset_position(void)
509 {
510 m_pos.reset();
511 m_next_pos.reset();
512 }
513
rnd_next(void)514 int table_events_waits_current::rnd_next(void)
515 {
516 PFS_thread *pfs_thread;
517 PFS_events_waits *wait;
518
519 for (m_pos.set_at(&m_next_pos);
520 m_pos.m_index_1 < thread_max;
521 m_pos.next_thread())
522 {
523 pfs_thread= &thread_array[m_pos.m_index_1];
524
525 if (! pfs_thread->m_lock.is_populated())
526 {
527 /* This thread does not exist */
528 continue;
529 }
530
531 /*
532 We do not show nested events for now,
533 this will be revised with TABLE io
534 */
535 #define ONLY_SHOW_ONE_WAIT
536
537 #ifdef ONLY_SHOW_ONE_WAIT
538 if (m_pos.m_index_2 >= 1)
539 continue;
540 #else
541 if (m_pos.m_index_2 >= pfs_thread->m_wait_locker_count)
542 continue;
543 #endif
544
545 wait= &pfs_thread->m_wait_locker_stack[m_pos.m_index_2].m_waits_current;
546
547 if (wait->m_wait_class == NO_WAIT_CLASS)
548 {
549 /*
550 This locker does not exist.
551 There can not be more lockers in the stack, skip to the next thread
552 */
553 continue;
554 }
555
556 make_row(true, pfs_thread, wait);
557 /* Next iteration, look for the next locker in this thread */
558 m_next_pos.set_after(&m_pos);
559 return 0;
560 }
561
562 return HA_ERR_END_OF_FILE;
563 }
564
rnd_pos(const void * pos)565 int table_events_waits_current::rnd_pos(const void *pos)
566 {
567 PFS_thread *pfs_thread;
568 PFS_events_waits *wait;
569
570 set_position(pos);
571 DBUG_ASSERT(m_pos.m_index_1 < thread_max);
572 pfs_thread= &thread_array[m_pos.m_index_1];
573
574 if (! pfs_thread->m_lock.is_populated())
575 return HA_ERR_RECORD_DELETED;
576
577 #ifdef ONLY_SHOW_CURRENT_WAITS
578 if (m_pos.m_index_2 >= pfs_thread->m_wait_locker_count)
579 return HA_ERR_RECORD_DELETED;
580 #endif
581
582 DBUG_ASSERT(m_pos.m_index_2 < LOCKER_STACK_SIZE);
583
584 wait= &pfs_thread->m_wait_locker_stack[m_pos.m_index_2].m_waits_current;
585
586 if (wait->m_wait_class == NO_WAIT_CLASS)
587 return HA_ERR_RECORD_DELETED;
588
589 make_row(true, pfs_thread, wait);
590 return 0;
591 }
592
delete_all_rows(void)593 int table_events_waits_current::delete_all_rows(void)
594 {
595 reset_events_waits_current();
596 return 0;
597 }
598
create(void)599 PFS_engine_table* table_events_waits_history::create(void)
600 {
601 return new table_events_waits_history();
602 }
603
table_events_waits_history()604 table_events_waits_history::table_events_waits_history()
605 : table_events_waits_common(&m_share, &m_pos),
606 m_pos(), m_next_pos()
607 {}
608
reset_position(void)609 void table_events_waits_history::reset_position(void)
610 {
611 m_pos.reset();
612 m_next_pos.reset();
613 }
614
rnd_next(void)615 int table_events_waits_history::rnd_next(void)
616 {
617 PFS_thread *pfs_thread;
618 PFS_events_waits *wait;
619
620 if (events_waits_history_per_thread == 0)
621 return HA_ERR_END_OF_FILE;
622
623 for (m_pos.set_at(&m_next_pos);
624 m_pos.m_index_1 < thread_max;
625 m_pos.next_thread())
626 {
627 pfs_thread= &thread_array[m_pos.m_index_1];
628
629 if (! pfs_thread->m_lock.is_populated())
630 {
631 /* This thread does not exist */
632 continue;
633 }
634
635 if (m_pos.m_index_2 >= events_waits_history_per_thread)
636 {
637 /* This thread does not have more (full) history */
638 continue;
639 }
640
641 if ( ! pfs_thread->m_waits_history_full &&
642 (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
643 {
644 /* This thread does not have more (not full) history */
645 continue;
646 }
647
648 if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class
649 == NO_WAIT_CLASS)
650 {
651 /*
652 This locker does not exist.
653 There can not be more lockers in the stack, skip to the next thread
654 */
655 continue;
656 }
657
658 wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
659
660 make_row(true, pfs_thread, wait);
661 /* Next iteration, look for the next history in this thread */
662 m_next_pos.set_after(&m_pos);
663 return 0;
664 }
665
666 return HA_ERR_END_OF_FILE;
667 }
668
rnd_pos(const void * pos)669 int table_events_waits_history::rnd_pos(const void *pos)
670 {
671 PFS_thread *pfs_thread;
672 PFS_events_waits *wait;
673
674 DBUG_ASSERT(events_waits_history_per_thread != 0);
675 set_position(pos);
676 DBUG_ASSERT(m_pos.m_index_1 < thread_max);
677 pfs_thread= &thread_array[m_pos.m_index_1];
678
679 if (! pfs_thread->m_lock.is_populated())
680 return HA_ERR_RECORD_DELETED;
681
682 DBUG_ASSERT(m_pos.m_index_2 < events_waits_history_per_thread);
683
684 if ( ! pfs_thread->m_waits_history_full &&
685 (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
686 return HA_ERR_RECORD_DELETED;
687
688 if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class
689 == NO_WAIT_CLASS)
690 return HA_ERR_RECORD_DELETED;
691
692 wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
693
694 make_row(true, pfs_thread, wait);
695 return 0;
696 }
697
delete_all_rows(void)698 int table_events_waits_history::delete_all_rows(void)
699 {
700 reset_events_waits_history();
701 return 0;
702 }
703
create(void)704 PFS_engine_table* table_events_waits_history_long::create(void)
705 {
706 return new table_events_waits_history_long();
707 }
708
table_events_waits_history_long()709 table_events_waits_history_long::table_events_waits_history_long()
710 : table_events_waits_common(&m_share, &m_pos),
711 m_pos(0), m_next_pos(0)
712 {}
713
reset_position(void)714 void table_events_waits_history_long::reset_position(void)
715 {
716 m_pos.m_index= 0;
717 m_next_pos.m_index= 0;
718 }
719
rnd_next(void)720 int table_events_waits_history_long::rnd_next(void)
721 {
722 PFS_events_waits *wait;
723 uint limit;
724
725 if (events_waits_history_long_size == 0)
726 return HA_ERR_END_OF_FILE;
727
728 if (events_waits_history_long_full)
729 limit= events_waits_history_long_size;
730 else
731 limit= events_waits_history_long_index % events_waits_history_long_size;
732
733 for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
734 {
735 wait= &events_waits_history_long_array[m_pos.m_index];
736
737 if (wait->m_wait_class != NO_WAIT_CLASS)
738 {
739 make_row(false, wait->m_thread, wait);
740 /* Next iteration, look for the next entry */
741 m_next_pos.set_after(&m_pos);
742 return 0;
743 }
744 }
745
746 return HA_ERR_END_OF_FILE;
747 }
748
rnd_pos(const void * pos)749 int table_events_waits_history_long::rnd_pos(const void *pos)
750 {
751 PFS_events_waits *wait;
752 uint limit;
753
754 if (events_waits_history_long_size == 0)
755 return HA_ERR_RECORD_DELETED;
756
757 set_position(pos);
758
759 if (events_waits_history_long_full)
760 limit= events_waits_history_long_size;
761 else
762 limit= events_waits_history_long_index % events_waits_history_long_size;
763
764 if (m_pos.m_index >= limit)
765 return HA_ERR_RECORD_DELETED;
766
767 wait= &events_waits_history_long_array[m_pos.m_index];
768
769 if (wait->m_wait_class == NO_WAIT_CLASS)
770 return HA_ERR_RECORD_DELETED;
771
772 make_row(false, wait->m_thread, wait);
773 return 0;
774 }
775
delete_all_rows(void)776 int table_events_waits_history_long::delete_all_rows(void)
777 {
778 reset_events_waits_history_long();
779 return 0;
780 }
781
782