1 /* Copyright (c) 2008, 2013, 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/pfs_events_waits.cc
18   Events waits data structures (implementation).
19 */
20 
21 #include "my_global.h"
22 #include "my_sys.h"
23 #include "pfs_global.h"
24 #include "pfs_instr.h"
25 #include "pfs_events_waits.h"
26 #include "pfs_atomic.h"
27 #include "m_string.h"
28 
29 ulong events_waits_history_long_size= 0;
30 /** Consumer flag for table EVENTS_WAITS_CURRENT. */
31 bool flag_events_waits_current= true;
32 /** Consumer flag for table EVENTS_WAITS_HISTORY. */
33 bool flag_events_waits_history= true;
34 /** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */
35 bool flag_events_waits_history_long= true;
36 /** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */
37 bool flag_events_waits_summary_by_thread_by_event_name= true;
38 /** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_EVENT_NAME. */
39 bool flag_events_waits_summary_by_event_name= true;
40 /** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_INSTANCE. */
41 bool flag_events_waits_summary_by_instance= true;
42 bool flag_events_locks_summary_by_event_name= true;
43 bool flag_events_locks_summary_by_instance= true;
44 /** Consumer flag for table FILE_SUMMARY_BY_EVENT_NAME. */
45 bool flag_file_summary_by_event_name= true;
46 /** Consumer flag for table FILE_SUMMARY_BY_INSTANCE. */
47 bool flag_file_summary_by_instance= true;
48 
49 /** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */
50 bool events_waits_history_long_full= false;
51 /** Index in EVENTS_WAITS_HISTORY_LONG circular buffer. */
52 volatile uint32 events_waits_history_long_index= 0;
53 /** EVENTS_WAITS_HISTORY_LONG circular buffer. */
54 PFS_events_waits *events_waits_history_long_array= NULL;
55 
56 /**
57   Initialize table EVENTS_WAITS_HISTORY_LONG.
58   @param events_waits_history_long_sizing       table sizing
59 */
init_events_waits_history_long(uint events_waits_history_long_sizing)60 int init_events_waits_history_long(uint events_waits_history_long_sizing)
61 {
62   events_waits_history_long_size= events_waits_history_long_sizing;
63   events_waits_history_long_full= false;
64   PFS_atomic::store_u32(&events_waits_history_long_index, 0);
65 
66   if (events_waits_history_long_size == 0)
67     return 0;
68 
69   events_waits_history_long_array=
70     PFS_MALLOC_ARRAY(events_waits_history_long_size, PFS_events_waits,
71                      MYF(MY_ZEROFILL));
72 
73   return (events_waits_history_long_array ? 0 : 1);
74 }
75 
76 /** Cleanup table EVENTS_WAITS_HISTORY_LONG. */
cleanup_events_waits_history_long(void)77 void cleanup_events_waits_history_long(void)
78 {
79   pfs_free(events_waits_history_long_array);
80   events_waits_history_long_array= NULL;
81 }
82 
copy_events_waits(PFS_events_waits * dest,const PFS_events_waits * source)83 static inline void copy_events_waits(PFS_events_waits *dest,
84                                      const PFS_events_waits *source)
85 {
86   memcpy(dest, source, sizeof(PFS_events_waits));
87 }
88 
89 /**
90   Insert a wait record in table EVENTS_WAITS_HISTORY.
91   @param thread             thread that executed the wait
92   @param wait               record to insert
93 */
insert_events_waits_history(PFS_thread * thread,PFS_events_waits * wait)94 void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait)
95 {
96   if (unlikely(events_waits_history_per_thread == 0))
97     return;
98 
99   uint index= thread->m_waits_history_index;
100 
101   /*
102     A concurrent thread executing TRUNCATE TABLE EVENTS_WAITS_CURRENT
103     could alter the data that this thread is inserting,
104     causing a potential race condition.
105     We are not testing for this and insert a possibly empty record,
106     to make this thread (the writer) faster.
107     This is ok, the readers of m_waits_history will filter this out.
108   */
109   copy_events_waits(&thread->m_waits_history[index], wait);
110 
111   index++;
112   if (index >= events_waits_history_per_thread)
113   {
114     index= 0;
115     thread->m_waits_history_full= true;
116   }
117   thread->m_waits_history_index= index;
118 }
119 
120 /**
121   Insert a wait record in table EVENTS_WAITS_HISTORY_LONG.
122   @param wait               record to insert
123 */
insert_events_waits_history_long(PFS_events_waits * wait)124 void insert_events_waits_history_long(PFS_events_waits *wait)
125 {
126   if (unlikely(events_waits_history_long_size == 0))
127     return;
128 
129   uint index= PFS_atomic::add_u32(&events_waits_history_long_index, 1);
130 
131   index= index % events_waits_history_long_size;
132   if (index == 0)
133     events_waits_history_long_full= true;
134 
135   /* See related comment in insert_events_waits_history. */
136   copy_events_waits(&events_waits_history_long_array[index], wait);
137 }
138 
139 /** Reset table EVENTS_WAITS_CURRENT data. */
reset_events_waits_current(void)140 void reset_events_waits_current(void)
141 {
142   PFS_thread *pfs_thread= thread_array;
143   PFS_thread *pfs_thread_last= thread_array + thread_max;
144 
145   for ( ; pfs_thread < pfs_thread_last; pfs_thread++)
146   {
147     PFS_wait_locker *locker= pfs_thread->m_wait_locker_stack;
148     PFS_wait_locker *locker_last= locker + LOCKER_STACK_SIZE;
149 
150     for ( ; locker < locker_last; locker++)
151       locker->m_waits_current.m_wait_class= NO_WAIT_CLASS;
152   }
153 }
154 
155 /** Reset table EVENTS_WAITS_HISTORY data. */
reset_events_waits_history(void)156 void reset_events_waits_history(void)
157 {
158   PFS_thread *pfs_thread= thread_array;
159   PFS_thread *pfs_thread_last= thread_array + thread_max;
160 
161   for ( ; pfs_thread < pfs_thread_last; pfs_thread++)
162   {
163     PFS_events_waits *wait= pfs_thread->m_waits_history;
164     PFS_events_waits *wait_last= wait + events_waits_history_per_thread;
165 
166     pfs_thread->m_waits_history_index= 0;
167     pfs_thread->m_waits_history_full= false;
168     for ( ; wait < wait_last; wait++)
169       wait->m_wait_class= NO_WAIT_CLASS;
170   }
171 }
172 
173 /** Reset table EVENTS_WAITS_HISTORY_LONG data. */
reset_events_waits_history_long(void)174 void reset_events_waits_history_long(void)
175 {
176   PFS_atomic::store_u32(&events_waits_history_long_index, 0);
177   events_waits_history_long_full= false;
178 
179   PFS_events_waits *wait= events_waits_history_long_array;
180   PFS_events_waits *wait_last= wait + events_waits_history_long_size;
181   for ( ; wait < wait_last; wait++)
182     wait->m_wait_class= NO_WAIT_CLASS;
183 }
184 
185