MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
table_events_waits.cc
Go to the documentation of this file.
1 /* Copyright (c) 2008, 2011, 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 
21 #include "my_global.h"
22 #include "my_pthread.h"
23 #include "table_events_waits.h"
24 #include "pfs_global.h"
25 #include "pfs_instr_class.h"
26 #include "pfs_instr.h"
27 #include "pfs_events_waits.h"
28 #include "pfs_timer.h"
29 #include "m_string.h"
30 
31 THR_LOCK table_events_waits_current::m_table_lock;
32 
33 static const TABLE_FIELD_TYPE field_types[]=
34 {
35  {
36  { C_STRING_WITH_LEN("THREAD_ID") },
37  { C_STRING_WITH_LEN("bigint(20)") },
38  { NULL, 0}
39  },
40  {
41  { C_STRING_WITH_LEN("EVENT_ID") },
42  { C_STRING_WITH_LEN("bigint(20)") },
43  { NULL, 0}
44  },
45  {
46  { C_STRING_WITH_LEN("END_EVENT_ID") },
47  { C_STRING_WITH_LEN("bigint(20)") },
48  { NULL, 0}
49  },
50  {
51  { C_STRING_WITH_LEN("EVENT_NAME") },
52  { C_STRING_WITH_LEN("varchar(128)") },
53  { NULL, 0}
54  },
55  {
56  { C_STRING_WITH_LEN("SOURCE") },
57  { C_STRING_WITH_LEN("varchar(64)") },
58  { NULL, 0}
59  },
60  {
61  { C_STRING_WITH_LEN("TIMER_START") },
62  { C_STRING_WITH_LEN("bigint(20)") },
63  { NULL, 0}
64  },
65  {
66  { C_STRING_WITH_LEN("TIMER_END") },
67  { C_STRING_WITH_LEN("bigint(20)") },
68  { NULL, 0}
69  },
70  {
71  { C_STRING_WITH_LEN("TIMER_WAIT") },
72  { C_STRING_WITH_LEN("bigint(20)") },
73  { NULL, 0}
74  },
75  {
76  { C_STRING_WITH_LEN("SPINS") },
77  { C_STRING_WITH_LEN("int(10)") },
78  { NULL, 0}
79  },
80  {
81  { C_STRING_WITH_LEN("OBJECT_SCHEMA") },
82  { C_STRING_WITH_LEN("varchar(64)") },
83  { NULL, 0}
84  },
85  {
86  { C_STRING_WITH_LEN("OBJECT_NAME") },
87  { C_STRING_WITH_LEN("varchar(512)") },
88  { NULL, 0}
89  },
90  {
91  { C_STRING_WITH_LEN("INDEX_NAME") },
92  { C_STRING_WITH_LEN("varchar(64)") },
93  { NULL, 0}
94  },
95  {
96  { C_STRING_WITH_LEN("OBJECT_TYPE") },
97  { C_STRING_WITH_LEN("varchar(64)") },
98  { NULL, 0}
99  },
100  {
101  { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
102  { C_STRING_WITH_LEN("bigint(20)") },
103  { NULL, 0}
104  },
105  {
106  { C_STRING_WITH_LEN("NESTING_EVENT_ID") },
107  { C_STRING_WITH_LEN("bigint(20)") },
108  { NULL, 0}
109  },
110  {
111  { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") },
112  { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") },
113  { NULL, 0}
114  },
115  {
116  { C_STRING_WITH_LEN("OPERATION") },
117  { C_STRING_WITH_LEN("varchar(32)") },
118  { NULL, 0}
119  },
120  {
121  { C_STRING_WITH_LEN("NUMBER_OF_BYTES") },
122  { C_STRING_WITH_LEN("bigint(20)") },
123  { NULL, 0}
124  },
125  {
126  { C_STRING_WITH_LEN("FLAGS") },
127  { C_STRING_WITH_LEN("int(10)") },
128  { NULL, 0}
129  }
130 };
131 
133 table_events_waits_current::m_field_def=
134 { 19, field_types };
135 
138 {
139  { C_STRING_WITH_LEN("events_waits_current") },
141  &table_events_waits_current::create,
142  NULL, /* write_row */
143  &table_events_waits_current::delete_all_rows,
144  NULL, /* get_row_count */
145  1000, /* records */
146  sizeof(pos_events_waits_current), /* ref length */
147  &m_table_lock,
148  &m_field_def,
149  false /* checked */
150 };
151 
152 THR_LOCK table_events_waits_history::m_table_lock;
153 
156 {
157  { C_STRING_WITH_LEN("events_waits_history") },
159  &table_events_waits_history::create,
160  NULL, /* write_row */
161  &table_events_waits_history::delete_all_rows,
162  NULL, /* get_row_count */
163  1000, /* records */
164  sizeof(pos_events_waits_history), /* ref length */
165  &m_table_lock,
166  &table_events_waits_current::m_field_def,
167  false /* checked */
168 };
169 
170 THR_LOCK table_events_waits_history_long::m_table_lock;
171 
174 {
175  { C_STRING_WITH_LEN("events_waits_history_long") },
177  &table_events_waits_history_long::create,
178  NULL, /* write_row */
179  &table_events_waits_history_long::delete_all_rows,
180  NULL, /* get_row_count */
181  10000, /* records */
182  sizeof(PFS_simple_index), /* ref length */
183  &m_table_lock,
184  &table_events_waits_current::m_field_def,
185  false /* checked */
186 };
187 
188 table_events_waits_common::table_events_waits_common
189 (const PFS_engine_table_share *share, void *pos)
190  : PFS_engine_table(share, pos),
191  m_row_exists(false)
192 {}
193 
194 void table_events_waits_common::clear_object_columns()
195 {
196  m_row.m_object_type= NULL;
202 }
203 
204 int table_events_waits_common::make_table_object_columns(volatile PFS_events_waits *wait)
205 {
206  uint safe_index;
207  PFS_table_share *safe_table_share;
208 
209  safe_table_share= sanitize_table_share(wait->m_weak_table_share);
210  if (unlikely(safe_table_share == NULL))
211  return 1;
212 
213  if (wait->m_object_type == OBJECT_TYPE_TABLE)
214  {
215  m_row.m_object_type= "TABLE";
217  }
218  else
219  {
220  m_row.m_object_type= "TEMPORARY TABLE";
222  }
223 
224  if (safe_table_share->get_version() == wait->m_weak_version)
225  {
226  /* OBJECT SCHEMA */
228  if (unlikely((m_row.m_object_schema_length == 0) ||
230  return 1;
231  memcpy(m_row.m_object_schema, safe_table_share->m_schema_name, m_row.m_object_schema_length);
232 
233  /* OBJECT NAME */
235  if (unlikely((m_row.m_object_name_length == 0) ||
237  return 1;
238  memcpy(m_row.m_object_name, safe_table_share->m_table_name, m_row.m_object_name_length);
239 
240  /* INDEX NAME */
241  safe_index= wait->m_index;
242  uint safe_key_count= sanitize_index_count(safe_table_share->m_key_count);
243  if (safe_index < safe_key_count)
244  {
245  PFS_table_key *key= & safe_table_share->m_keys[safe_index];
247  if (unlikely((m_row.m_index_name_length == 0) ||
249  return 1;
251  }
252  else
254  }
255  else
256  {
260  }
261 
263  return 0;
264 }
265 
266 int table_events_waits_common::make_file_object_columns(volatile PFS_events_waits *wait)
267 {
268  PFS_file *safe_file;
269 
270  safe_file= sanitize_file(wait->m_weak_file);
271  if (unlikely(safe_file == NULL))
272  return 1;
273 
274  m_row.m_object_type= "FILE";
278 
279  if (safe_file->get_version() == wait->m_weak_version)
280  {
281  /* OBJECT NAME */
283  if (unlikely((m_row.m_object_name_length == 0) ||
285  return 1;
287  }
288  else
289  {
291  }
292 
294 
295  return 0;
296 }
297 
298 int table_events_waits_common::make_socket_object_columns(volatile PFS_events_waits *wait)
299 {
300  PFS_socket *safe_socket;
301 
302  safe_socket= sanitize_socket(wait->m_weak_socket);
303  if (unlikely(safe_socket == NULL))
304  return 1;
305 
306  m_row.m_object_type= "SOCKET";
310 
311  if (safe_socket->get_version() == wait->m_weak_version)
312  {
313  /* Convert port number to string, include delimiter in port name length */
314 
315  uint port;
316  char port_str[128];
317  char ip_str[INET6_ADDRSTRLEN+1];
318  uint ip_len= 0;
319  port_str[0]= ':';
320 
321  /* Get the IP address and port number */
322  ip_len= pfs_get_socket_address(ip_str, sizeof(ip_str), &port,
323  &safe_socket->m_sock_addr,
324  safe_socket->m_addr_len);
325 
326  /* Convert port number to a string (length includes ':') */
327  int port_len= int10_to_str(port, (port_str+1), 10) - port_str + 1;
328 
329  /* OBJECT NAME */
330  m_row.m_object_name_length= ip_len + port_len;
331 
332  if (unlikely((m_row.m_object_name_length == 0) ||
334  return 1;
335 
336  char *name= m_row.m_object_name;
337  memcpy(name, ip_str, ip_len);
338  memcpy(name + ip_len, port_str, port_len);
339  }
340  else
341  {
343  }
344 
346 
347  return 0;
348 }
349 
357 void table_events_waits_common::make_row(bool thread_own_wait,
358  PFS_thread *pfs_thread,
359  volatile PFS_events_waits *wait)
360 {
361  pfs_lock lock;
362  PFS_thread *safe_thread;
363  PFS_instr_class *safe_class;
364  const char *base;
365  const char *safe_source_file;
366 
367  m_row_exists= false;
368  safe_thread= sanitize_thread(pfs_thread);
369  if (unlikely(safe_thread == NULL))
370  return;
371 
372  /* Protect this reader against a thread termination */
373  if (thread_own_wait)
374  safe_thread->m_lock.begin_optimistic_lock(&lock);
375 
376  /*
377  Design choice:
378  We could have used a pfs_lock in PFS_events_waits here,
379  to protect the reader from concurrent event generation,
380  but this leads to too many pfs_lock atomic operations
381  each time an event is recorded:
382  - 1 dirty() + 1 allocated() per event start, for EVENTS_WAITS_CURRENT
383  - 1 dirty() + 1 allocated() per event end, for EVENTS_WAITS_CURRENT
384  - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY
385  - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY_LONG
386  or 8 atomics per recorded event.
387  The problem is that we record a *lot* of events ...
388 
389  This code is prepared to accept *dirty* records,
390  and sanitizes all the data before returning a row.
391  */
392 
393  /*
394  PFS_events_waits::m_class needs to be sanitized,
395  for race conditions when this code:
396  - reads a new value in m_wait_class,
397  - reads an old value in m_class.
398  */
399  switch (wait->m_wait_class)
400  {
401  case WAIT_CLASS_IDLE:
402  clear_object_columns();
403  safe_class= sanitize_idle_class(wait->m_class);
404  break;
405  case WAIT_CLASS_MUTEX:
406  clear_object_columns();
407  safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class);
408  break;
409  case WAIT_CLASS_RWLOCK:
410  clear_object_columns();
411  safe_class= sanitize_rwlock_class((PFS_rwlock_class*) wait->m_class);
412  break;
413  case WAIT_CLASS_COND:
414  clear_object_columns();
415  safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class);
416  break;
417  case WAIT_CLASS_TABLE:
418  if (make_table_object_columns(wait))
419  return;
420  safe_class= sanitize_table_class(wait->m_class);
421  break;
422  case WAIT_CLASS_FILE:
423  if (make_file_object_columns(wait))
424  return;
425  safe_class= sanitize_file_class((PFS_file_class*) wait->m_class);
426  break;
427  case WAIT_CLASS_SOCKET:
428  if (make_socket_object_columns(wait))
429  return;
430  safe_class= sanitize_socket_class((PFS_socket_class*) wait->m_class);
431  break;
432  case NO_WAIT_CLASS:
433  default:
434  return;
435  }
436 
437  if (unlikely(safe_class == NULL))
438  return;
439 
441  m_row.m_event_id= wait->m_event_id;
445 
446  get_normalizer(safe_class);
449 
450  m_row.m_name= safe_class->m_name;
451  m_row.m_name_length= safe_class->m_name_length;
452 
453  /*
454  We are assuming this pointer is sane,
455  since it comes from __FILE__.
456  */
457  safe_source_file= wait->m_source_file;
458  if (unlikely(safe_source_file == NULL))
459  return;
460 
461  base= base_name(wait->m_source_file);
462  m_row.m_source_length= my_snprintf(m_row.m_source, sizeof(m_row.m_source),
463  "%s:%d", base, wait->m_source_line);
464  if (m_row.m_source_length > sizeof(m_row.m_source))
468  m_row.m_flags= wait->m_flags;
469 
470  if (thread_own_wait)
471  {
472  if (safe_thread->m_lock.end_optimistic_lock(&lock))
473  m_row_exists= true;
474  }
475  else
476  {
477  /*
478  For EVENTS_WAITS_HISTORY_LONG (thread_own_wait is false),
479  the wait record is always valid, because it is not stored
480  in memory owned by pfs_thread.
481  Even when the thread terminated, the record is mostly readable,
482  so this record is displayed.
483  */
484  m_row_exists= true;
485  }
486 }
487 
496 static const LEX_STRING operation_names_map[]=
497 {
498  /* Mutex operations */
499  { C_STRING_WITH_LEN("lock") },
500  { C_STRING_WITH_LEN("try_lock") },
501 
502  /* RWLock operations */
503  { C_STRING_WITH_LEN("read_lock") },
504  { C_STRING_WITH_LEN("write_lock") },
505  { C_STRING_WITH_LEN("try_read_lock") },
506  { C_STRING_WITH_LEN("try_write_lock") },
507 
508  /* Condition operations */
509  { C_STRING_WITH_LEN("wait") },
510  { C_STRING_WITH_LEN("timed_wait") },
511 
512  /* File operations */
513  { C_STRING_WITH_LEN("create") },
514  { C_STRING_WITH_LEN("create") }, /* create tmp */
515  { C_STRING_WITH_LEN("open") },
516  { C_STRING_WITH_LEN("open") }, /* stream open */
517  { C_STRING_WITH_LEN("close") },
518  { C_STRING_WITH_LEN("close") }, /* stream close */
519  { C_STRING_WITH_LEN("read") },
520  { C_STRING_WITH_LEN("write") },
521  { C_STRING_WITH_LEN("seek") },
522  { C_STRING_WITH_LEN("tell") },
523  { C_STRING_WITH_LEN("flush") },
524  { C_STRING_WITH_LEN("stat") },
525  { C_STRING_WITH_LEN("stat") }, /* fstat */
526  { C_STRING_WITH_LEN("chsize") },
527  { C_STRING_WITH_LEN("delete") },
528  { C_STRING_WITH_LEN("rename") },
529  { C_STRING_WITH_LEN("sync") },
530 
531  /* Table io operations */
532  { C_STRING_WITH_LEN("fetch") },
533  { C_STRING_WITH_LEN("insert") }, /* write row */
534  { C_STRING_WITH_LEN("update") }, /* update row */
535  { C_STRING_WITH_LEN("delete") }, /* delete row */
536 
537  /* Table lock operations */
538  { C_STRING_WITH_LEN("read normal") },
539  { C_STRING_WITH_LEN("read with shared locks") },
540  { C_STRING_WITH_LEN("read high priority") },
541  { C_STRING_WITH_LEN("read no inserts") },
542  { C_STRING_WITH_LEN("write allow write") },
543  { C_STRING_WITH_LEN("write concurrent insert") },
544  { C_STRING_WITH_LEN("write delayed") },
545  { C_STRING_WITH_LEN("write low priority") },
546  { C_STRING_WITH_LEN("write normal") },
547  { C_STRING_WITH_LEN("read external") },
548  { C_STRING_WITH_LEN("write external") },
549 
550  /* Socket operations */
551  { C_STRING_WITH_LEN("create") },
552  { C_STRING_WITH_LEN("connect") },
553  { C_STRING_WITH_LEN("bind") },
554  { C_STRING_WITH_LEN("close") },
555  { C_STRING_WITH_LEN("send") },
556  { C_STRING_WITH_LEN("recv") },
557  { C_STRING_WITH_LEN("sendto") },
558  { C_STRING_WITH_LEN("recvfrom") },
559  { C_STRING_WITH_LEN("sendmsg") },
560  { C_STRING_WITH_LEN("recvmsg") },
561  { C_STRING_WITH_LEN("seek") },
562  { C_STRING_WITH_LEN("opt") },
563  { C_STRING_WITH_LEN("stat") },
564  { C_STRING_WITH_LEN("shutdown") },
565  { C_STRING_WITH_LEN("select") },
566 
567  /* Idle operations */
568  { C_STRING_WITH_LEN("idle") }
569 };
570 
571 
573  unsigned char *buf,
574  Field **fields,
575  bool read_all)
576 {
577  Field *f;
578  const LEX_STRING *operation;
579 
580  compile_time_assert(COUNT_OPERATION_TYPE ==
581  array_elements(operation_names_map));
582 
583  if (unlikely(! m_row_exists))
584  return HA_ERR_RECORD_DELETED;
585 
586  /* Set the null bits */
587  DBUG_ASSERT(table->s->null_bytes == 2);
588  buf[0]= 0;
589  buf[1]= 0;
590 
591  /*
592  Some columns are unreliable, because they are joined with other buffers,
593  which could have changed and been reused for something else.
594  These columns are:
595  - THREAD_ID (m_thread joins with PFS_thread),
596  - SCHEMA_NAME (m_schema_name joins with PFS_table_share)
597  - OBJECT_NAME (m_object_name joins with PFS_table_share)
598  */
599  for (; (f= *fields) ; fields++)
600  {
601  if (read_all || bitmap_is_set(table->read_set, f->field_index))
602  {
603  switch(f->field_index)
604  {
605  case 0: /* THREAD_ID */
607  break;
608  case 1: /* EVENT_ID */
610  break;
611  case 2: /* END_EVENT_ID */
612  if (m_row.m_end_event_id > 0)
614  else
615  f->set_null();
616  break;
617  case 3: /* EVENT_NAME */
619  break;
620  case 4: /* SOURCE */
622  break;
623  case 5: /* TIMER_START */
624  if (m_row.m_timer_start != 0)
626  else
627  f->set_null();
628  break;
629  case 6: /* TIMER_END */
630  if (m_row.m_timer_end != 0)
632  else
633  f->set_null();
634  break;
635  case 7: /* TIMER_WAIT */
636  if (m_row.m_timer_wait != 0)
638  else
639  f->set_null();
640  break;
641  case 8: /* SPINS */
642  f->set_null();
643  break;
644  case 9: /* OBJECT_SCHEMA */
646  {
649  }
650  else
651  f->set_null();
652  break;
653  case 10: /* OBJECT_NAME */
654  if (m_row.m_object_name_length > 0)
655  {
658  }
659  else
660  f->set_null();
661  break;
662  case 11: /* INDEX_NAME */
663  if (m_row.m_index_name_length > 0)
664  {
667  }
668  else
669  f->set_null();
670  break;
671  case 12: /* OBJECT_TYPE */
672  if (m_row.m_object_type)
673  {
676  }
677  else
678  f->set_null();
679  break;
680  case 13: /* OBJECT_INSTANCE */
682  break;
683  case 14: /* NESTING_EVENT_ID */
684  if (m_row.m_nesting_event_id != 0)
686  else
687  f->set_null();
688  break;
689  case 15: /* NESTING_EVENT_TYPE */
690  if (m_row.m_nesting_event_id != 0)
692  else
693  f->set_null();
694  break;
695  case 16: /* OPERATION */
696  operation= &operation_names_map[(int) m_row.m_operation - 1];
697  set_field_varchar_utf8(f, operation->str, operation->length);
698  break;
699  case 17: /* NUMBER_OF_BYTES */
700  if ((m_row.m_operation == OPERATION_TYPE_FILEREAD) ||
701  (m_row.m_operation == OPERATION_TYPE_FILEWRITE) ||
702  (m_row.m_operation == OPERATION_TYPE_FILECHSIZE) ||
703  (m_row.m_operation == OPERATION_TYPE_SOCKETSEND) ||
704  (m_row.m_operation == OPERATION_TYPE_SOCKETRECV) ||
705  (m_row.m_operation == OPERATION_TYPE_SOCKETSENDTO) ||
706  (m_row.m_operation == OPERATION_TYPE_SOCKETRECVFROM))
708  else
709  f->set_null();
710  break;
711  case 18: /* FLAGS */
712  f->set_null();
713  break;
714  default:
715  DBUG_ASSERT(false);
716  }
717  }
718  }
719  return 0;
720 }
721 
722 PFS_engine_table* table_events_waits_current::create(void)
723 {
724  return new table_events_waits_current();
725 }
726 
727 table_events_waits_current::table_events_waits_current()
728  : table_events_waits_common(&m_share, &m_pos),
729  m_pos(), m_next_pos()
730 {}
731 
733 {
734  m_pos.reset();
735  m_next_pos.reset();
736 }
737 
739 {
740  PFS_thread *pfs_thread;
741  PFS_events_waits *wait;
742 
743  for (m_pos.set_at(&m_next_pos);
744  m_pos.m_index_1 < thread_max;
745  m_pos.next_thread())
746  {
747  pfs_thread= &thread_array[m_pos.m_index_1];
748 
749  if (! pfs_thread->m_lock.is_populated())
750  {
751  /* This thread does not exist */
752  continue;
753  }
754 
755  /*
756  We do not show nested events for now,
757  this will be revised with TABLE io
758  */
759 // #define ONLY_SHOW_ONE_WAIT
760 
761 #ifdef ONLY_SHOW_ONE_WAIT
762  if (m_pos.m_index_2 >= 1)
763  continue;
764 #else
765  /* m_events_waits_stack[0] is a dummy record */
766  PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM];
767  wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM];
768 
769  PFS_events_waits *safe_current = pfs_thread->m_events_waits_current;
770 
771  if (safe_current == top_wait)
772  {
773  /* Display the last top level wait, when completed */
774  if (m_pos.m_index_2 >= 1)
775  continue;
776  }
777  else
778  {
779  /* Display all pending waits, when in progress */
780  if (wait >= safe_current)
781  continue;
782  }
783 #endif
784 
785  if (wait->m_wait_class == NO_WAIT_CLASS)
786  {
787  /*
788  This locker does not exist.
789  There can not be more lockers in the stack, skip to the next thread
790  */
791  continue;
792  }
793 
794  make_row(true, pfs_thread, wait);
795  /* Next iteration, look for the next locker in this thread */
796  m_next_pos.set_after(&m_pos);
797  return 0;
798  }
799 
800  return HA_ERR_END_OF_FILE;
801 }
802 
804 {
805  PFS_thread *pfs_thread;
806  PFS_events_waits *wait;
807 
808  set_position(pos);
809  DBUG_ASSERT(m_pos.m_index_1 < thread_max);
810  pfs_thread= &thread_array[m_pos.m_index_1];
811 
812  if (! pfs_thread->m_lock.is_populated())
813  return HA_ERR_RECORD_DELETED;
814 
815 #ifdef ONLY_SHOW_ONE_WAIT
816  if (m_pos.m_index_2 >= 1)
817  return HA_ERR_RECORD_DELETED;
818 #else
819  /* m_events_waits_stack[0] is a dummy record */
820  PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM];
821  wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM];
822 
823  PFS_events_waits *safe_current = pfs_thread->m_events_waits_current;
824 
825  if (safe_current == top_wait)
826  {
827  /* Display the last top level wait, when completed */
828  if (m_pos.m_index_2 >= 1)
829  return HA_ERR_RECORD_DELETED;
830  }
831  else
832  {
833  /* Display all pending waits, when in progress */
834  if (wait >= safe_current)
835  return HA_ERR_RECORD_DELETED;
836  }
837 #endif
838 
839  DBUG_ASSERT(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE);
840 
841  if (wait->m_wait_class == NO_WAIT_CLASS)
842  return HA_ERR_RECORD_DELETED;
843 
844  make_row(true, pfs_thread, wait);
845  return 0;
846 }
847 
848 int table_events_waits_current::delete_all_rows(void)
849 {
851  return 0;
852 }
853 
854 PFS_engine_table* table_events_waits_history::create(void)
855 {
856  return new table_events_waits_history();
857 }
858 
859 table_events_waits_history::table_events_waits_history()
860  : table_events_waits_common(&m_share, &m_pos),
861  m_pos(), m_next_pos()
862 {}
863 
865 {
866  m_pos.reset();
867  m_next_pos.reset();
868 }
869 
871 {
872  PFS_thread *pfs_thread;
873  PFS_events_waits *wait;
874 
876  return HA_ERR_END_OF_FILE;
877 
878  for (m_pos.set_at(&m_next_pos);
879  m_pos.m_index_1 < thread_max;
880  m_pos.next_thread())
881  {
882  pfs_thread= &thread_array[m_pos.m_index_1];
883 
884  if (! pfs_thread->m_lock.is_populated())
885  {
886  /* This thread does not exist */
887  continue;
888  }
889 
891  {
892  /* This thread does not have more (full) history */
893  continue;
894  }
895 
896  if ( ! pfs_thread->m_waits_history_full &&
897  (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
898  {
899  /* This thread does not have more (not full) history */
900  continue;
901  }
902 
903  if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class
904  == NO_WAIT_CLASS)
905  {
906  /*
907  This locker does not exist.
908  There can not be more lockers in the stack, skip to the next thread
909  */
910  continue;
911  }
912 
913  wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
914 
915  make_row(true, pfs_thread, wait);
916  /* Next iteration, look for the next history in this thread */
917  m_next_pos.set_after(&m_pos);
918  return 0;
919  }
920 
921  return HA_ERR_END_OF_FILE;
922 }
923 
925 {
926  PFS_thread *pfs_thread;
927  PFS_events_waits *wait;
928 
929  DBUG_ASSERT(events_waits_history_per_thread != 0);
930  set_position(pos);
931  DBUG_ASSERT(m_pos.m_index_1 < thread_max);
932  pfs_thread= &thread_array[m_pos.m_index_1];
933 
934  if (! pfs_thread->m_lock.is_populated())
935  return HA_ERR_RECORD_DELETED;
936 
937  DBUG_ASSERT(m_pos.m_index_2 < events_waits_history_per_thread);
938 
939  if ( ! pfs_thread->m_waits_history_full &&
940  (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
941  return HA_ERR_RECORD_DELETED;
942 
943  wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
944 
945  if (wait->m_wait_class == NO_WAIT_CLASS)
946  return HA_ERR_RECORD_DELETED;
947 
948  make_row(true, pfs_thread, wait);
949  return 0;
950 }
951 
952 int table_events_waits_history::delete_all_rows(void)
953 {
955  return 0;
956 }
957 
958 PFS_engine_table* table_events_waits_history_long::create(void)
959 {
960  return new table_events_waits_history_long();
961 }
962 
963 table_events_waits_history_long::table_events_waits_history_long()
964  : table_events_waits_common(&m_share, &m_pos),
965  m_pos(0), m_next_pos(0)
966 {}
967 
969 {
970  m_pos.m_index= 0;
971  m_next_pos.m_index= 0;
972 }
973 
975 {
976  PFS_events_waits *wait;
977  uint limit;
978 
979  if (events_waits_history_long_size == 0)
980  return HA_ERR_END_OF_FILE;
981 
983  limit= events_waits_history_long_size;
984  else
985  limit= events_waits_history_long_index % events_waits_history_long_size;
986 
987  for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
988  {
990 
991  if (wait->m_wait_class != NO_WAIT_CLASS)
992  {
993  make_row(false, wait->m_thread, wait);
994  /* Next iteration, look for the next entry */
995  m_next_pos.set_after(&m_pos);
996  return 0;
997  }
998  }
999 
1000  return HA_ERR_END_OF_FILE;
1001 }
1002 
1004 {
1005  PFS_events_waits *wait;
1006  uint limit;
1007 
1008  if (events_waits_history_long_size == 0)
1009  return HA_ERR_RECORD_DELETED;
1010 
1011  set_position(pos);
1012 
1014  limit= events_waits_history_long_size;
1015  else
1016  limit= events_waits_history_long_index % events_waits_history_long_size;
1017 
1018  if (m_pos.m_index >= limit)
1019  return HA_ERR_RECORD_DELETED;
1020 
1022 
1023  if (wait->m_wait_class == NO_WAIT_CLASS)
1024  return HA_ERR_RECORD_DELETED;
1025 
1026  make_row(false, wait->m_thread, wait);
1027  return 0;
1028 }
1029 
1030 int table_events_waits_history_long::delete_all_rows(void)
1031 {
1033  return 0;
1034 }
1035