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