1 /* Copyright (c) 2008, 2021, Oracle and/or its affiliates.
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, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 /**
24   @file storage/perfschema/pfs_events_waits.cc
25   Events waits data structures (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_sys.h"
30 #include "pfs_global.h"
31 #include "pfs_instr_class.h"
32 #include "pfs_instr.h"
33 #include "pfs_user.h"
34 #include "pfs_host.h"
35 #include "pfs_account.h"
36 #include "pfs_events_waits.h"
37 #include "pfs_atomic.h"
38 #include "pfs_buffer_container.h"
39 #include "pfs_builtin_memory.h"
40 #include "m_string.h"
41 
42 PFS_ALIGNED ulong events_waits_history_long_size= 0;
43 /** Consumer flag for table EVENTS_WAITS_CURRENT. */
44 PFS_ALIGNED bool flag_events_waits_current= false;
45 /** Consumer flag for table EVENTS_WAITS_HISTORY. */
46 PFS_ALIGNED bool flag_events_waits_history= false;
47 /** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */
48 PFS_ALIGNED bool flag_events_waits_history_long= false;
49 /** Consumer flag for the global instrumentation. */
50 PFS_ALIGNED bool flag_global_instrumentation= false;
51 /** Consumer flag for the per thread instrumentation. */
52 PFS_ALIGNED bool flag_thread_instrumentation= false;
53 
54 /** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */
55 PFS_ALIGNED bool events_waits_history_long_full= false;
56 /** Index in EVENTS_WAITS_HISTORY_LONG circular buffer. */
57 PFS_ALIGNED PFS_cacheline_uint32 events_waits_history_long_index;
58 /** EVENTS_WAITS_HISTORY_LONG circular buffer. */
59 PFS_ALIGNED PFS_events_waits *events_waits_history_long_array= NULL;
60 
61 /**
62   Initialize table EVENTS_WAITS_HISTORY_LONG.
63   @param events_waits_history_long_sizing       table sizing
64 */
init_events_waits_history_long(uint events_waits_history_long_sizing)65 int init_events_waits_history_long(uint events_waits_history_long_sizing)
66 {
67   events_waits_history_long_size= events_waits_history_long_sizing;
68   events_waits_history_long_full= false;
69   PFS_atomic::store_u32(&events_waits_history_long_index.m_u32, 0);
70 
71   if (events_waits_history_long_size == 0)
72     return 0;
73 
74   events_waits_history_long_array=
75     PFS_MALLOC_ARRAY(& builtin_memory_waits_history_long,
76                      events_waits_history_long_size,
77                      sizeof(PFS_events_waits), PFS_events_waits,
78                      MYF(MY_ZEROFILL));
79 
80   return (events_waits_history_long_array ? 0 : 1);
81 }
82 
83 /** Cleanup table EVENTS_WAITS_HISTORY_LONG. */
cleanup_events_waits_history_long(void)84 void cleanup_events_waits_history_long(void)
85 {
86   PFS_FREE_ARRAY(& builtin_memory_waits_history_long,
87                  events_waits_history_long_size, sizeof(PFS_events_waits),
88                  events_waits_history_long_array);
89   events_waits_history_long_array= NULL;
90 }
91 
copy_events_waits(PFS_events_waits * dest,const PFS_events_waits * source)92 static inline void copy_events_waits(PFS_events_waits *dest,
93                                      const PFS_events_waits *source)
94 {
95   memcpy(dest, source, sizeof(PFS_events_waits));
96 }
97 
98 /**
99   Insert a wait record in table EVENTS_WAITS_HISTORY.
100   @param thread             thread that executed the wait
101   @param wait               record to insert
102 */
insert_events_waits_history(PFS_thread * thread,PFS_events_waits * wait)103 void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait)
104 {
105   if (unlikely(events_waits_history_per_thread == 0))
106     return;
107 
108   uint index= thread->m_waits_history_index;
109 
110   /*
111     A concurrent thread executing TRUNCATE TABLE EVENTS_WAITS_CURRENT
112     could alter the data that this thread is inserting,
113     causing a potential race condition.
114     We are not testing for this and insert a possibly empty record,
115     to make this thread (the writer) faster.
116     This is ok, the readers of m_waits_history will filter this out.
117   */
118   copy_events_waits(&thread->m_waits_history[index], wait);
119 
120   index++;
121   if (index >= events_waits_history_per_thread)
122   {
123     index= 0;
124     thread->m_waits_history_full= true;
125   }
126   thread->m_waits_history_index= index;
127 }
128 
129 /**
130   Insert a wait record in table EVENTS_WAITS_HISTORY_LONG.
131   @param wait               record to insert
132 */
insert_events_waits_history_long(PFS_events_waits * wait)133 void insert_events_waits_history_long(PFS_events_waits *wait)
134 {
135   if (unlikely(events_waits_history_long_size == 0))
136     return;
137 
138   uint index= PFS_atomic::add_u32(&events_waits_history_long_index.m_u32, 1);
139 
140   index= index % events_waits_history_long_size;
141   if (index == 0)
142     events_waits_history_long_full= true;
143 
144   /* See related comment in insert_events_waits_history. */
145   copy_events_waits(&events_waits_history_long_array[index], wait);
146 }
147 
fct_reset_events_waits_current(PFS_thread * pfs_thread)148 static void fct_reset_events_waits_current(PFS_thread *pfs_thread)
149 {
150   PFS_events_waits *pfs_wait= pfs_thread->m_events_waits_stack;
151   PFS_events_waits *pfs_wait_last= pfs_wait + WAIT_STACK_SIZE;
152 
153   for ( ; pfs_wait < pfs_wait_last; pfs_wait++)
154     pfs_wait->m_wait_class= NO_WAIT_CLASS;
155 }
156 
157 
158 /** Reset table EVENTS_WAITS_CURRENT data. */
reset_events_waits_current(void)159 void reset_events_waits_current(void)
160 {
161   global_thread_container.apply_all(fct_reset_events_waits_current);
162 }
163 
fct_reset_events_waits_history(PFS_thread * pfs_thread)164 static void fct_reset_events_waits_history(PFS_thread *pfs_thread)
165 {
166   PFS_events_waits *wait= pfs_thread->m_waits_history;
167   PFS_events_waits *wait_last= wait + events_waits_history_per_thread;
168 
169   pfs_thread->m_waits_history_index= 0;
170   pfs_thread->m_waits_history_full= false;
171   for ( ; wait < wait_last; wait++)
172     wait->m_wait_class= NO_WAIT_CLASS;
173 }
174 
175 /** Reset table EVENTS_WAITS_HISTORY data. */
reset_events_waits_history(void)176 void reset_events_waits_history(void)
177 {
178   global_thread_container.apply_all(fct_reset_events_waits_history);
179 }
180 
181 /** Reset table EVENTS_WAITS_HISTORY_LONG data. */
reset_events_waits_history_long(void)182 void reset_events_waits_history_long(void)
183 {
184   PFS_atomic::store_u32(&events_waits_history_long_index.m_u32, 0);
185   events_waits_history_long_full= false;
186 
187   PFS_events_waits *wait= events_waits_history_long_array;
188   PFS_events_waits *wait_last= wait + events_waits_history_long_size;
189   for ( ; wait < wait_last; wait++)
190     wait->m_wait_class= NO_WAIT_CLASS;
191 }
192 
fct_reset_events_waits_by_thread(PFS_thread * thread)193 static void fct_reset_events_waits_by_thread(PFS_thread *thread)
194 {
195   PFS_account *account= sanitize_account(thread->m_account);
196   PFS_user *user= sanitize_user(thread->m_user);
197   PFS_host *host= sanitize_host(thread->m_host);
198   aggregate_thread_waits(thread, account, user, host);
199 }
200 
201 /** Reset table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
reset_events_waits_by_thread()202 void reset_events_waits_by_thread()
203 {
204   global_thread_container.apply(fct_reset_events_waits_by_thread);
205 }
206 
fct_reset_events_waits_by_account(PFS_account * pfs)207 static void fct_reset_events_waits_by_account(PFS_account *pfs)
208 {
209   PFS_user *user= sanitize_user(pfs->m_user);
210   PFS_host *host= sanitize_host(pfs->m_host);
211   pfs->aggregate_waits(user, host);
212 }
213 
214 /** Reset table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
reset_events_waits_by_account()215 void reset_events_waits_by_account()
216 {
217   global_account_container.apply(fct_reset_events_waits_by_account);
218 }
219 
fct_reset_events_waits_by_user(PFS_user * pfs)220 static void fct_reset_events_waits_by_user(PFS_user *pfs)
221 {
222   pfs->aggregate_waits();
223 }
224 
225 /** Reset table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
reset_events_waits_by_user()226 void reset_events_waits_by_user()
227 {
228   global_user_container.apply(fct_reset_events_waits_by_user);
229 }
230 
fct_reset_events_waits_by_host(PFS_host * pfs)231 static void fct_reset_events_waits_by_host(PFS_host *pfs)
232 {
233   pfs->aggregate_waits();
234 }
235 
236 /** Reset table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
reset_events_waits_by_host()237 void reset_events_waits_by_host()
238 {
239   global_host_container.apply(fct_reset_events_waits_by_host);
240 }
241 
fct_reset_table_waits_by_table(PFS_table_share * pfs)242 static void fct_reset_table_waits_by_table(PFS_table_share *pfs)
243 {
244   pfs->aggregate();
245 }
246 
reset_table_waits_by_table()247 void reset_table_waits_by_table()
248 {
249   global_table_share_container.apply(fct_reset_table_waits_by_table);
250 }
251 
fct_reset_table_io_waits_by_table(PFS_table_share * pfs)252 static void fct_reset_table_io_waits_by_table(PFS_table_share *pfs)
253 {
254   pfs->aggregate_io();
255 }
256 
reset_table_io_waits_by_table()257 void reset_table_io_waits_by_table()
258 {
259   global_table_share_container.apply(fct_reset_table_io_waits_by_table);
260 }
261 
fct_reset_table_lock_waits_by_table(PFS_table_share * pfs)262 static void fct_reset_table_lock_waits_by_table(PFS_table_share *pfs)
263 {
264   pfs->aggregate_lock();
265 }
266 
reset_table_lock_waits_by_table()267 void reset_table_lock_waits_by_table()
268 {
269   global_table_share_container.apply(fct_reset_table_lock_waits_by_table);
270 }
271 
fct_reset_table_waits_by_table_handle(PFS_table * pfs)272 void fct_reset_table_waits_by_table_handle(PFS_table *pfs)
273 {
274   pfs->sanitized_aggregate();
275 }
276 
reset_table_waits_by_table_handle()277 void reset_table_waits_by_table_handle()
278 {
279   global_table_container.apply(fct_reset_table_waits_by_table_handle);
280 }
281 
fct_reset_table_io_waits_by_table_handle(PFS_table * pfs)282 void fct_reset_table_io_waits_by_table_handle(PFS_table *pfs)
283 {
284   pfs->sanitized_aggregate_io();
285 }
286 
reset_table_io_waits_by_table_handle()287 void reset_table_io_waits_by_table_handle()
288 {
289   global_table_container.apply(fct_reset_table_io_waits_by_table_handle);
290 }
291 
fct_reset_table_lock_waits_by_table_handle(PFS_table * pfs)292 void fct_reset_table_lock_waits_by_table_handle(PFS_table *pfs)
293 {
294   pfs->sanitized_aggregate_lock();
295 }
296 
reset_table_lock_waits_by_table_handle()297 void reset_table_lock_waits_by_table_handle()
298 {
299   global_table_container.apply(fct_reset_table_lock_waits_by_table_handle);
300 }
301 
302