1 /* Copyright (c) 2008, 2020, 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, 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
21   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /**
24   @file storage/perfschema/pfs_events_waits.cc
25   Events waits data structures (implementation).
26 */
27 
28 #include "storage/perfschema/pfs_events_waits.h"
29 
30 #include <atomic>
31 
32 #include "m_string.h"
33 #include "my_compiler.h"
34 #include "my_sys.h"
35 #include "storage/perfschema/pfs_account.h"
36 #include "storage/perfschema/pfs_buffer_container.h"
37 #include "storage/perfschema/pfs_builtin_memory.h"
38 #include "storage/perfschema/pfs_global.h"
39 #include "storage/perfschema/pfs_host.h"
40 #include "storage/perfschema/pfs_instr.h"
41 #include "storage/perfschema/pfs_instr_class.h"
42 #include "storage/perfschema/pfs_user.h"
43 
44 PFS_ALIGNED ulong events_waits_history_long_size = 0;
45 /** Consumer flag for table EVENTS_WAITS_CURRENT. */
46 PFS_ALIGNED bool flag_events_waits_current = false;
47 /** Consumer flag for table EVENTS_WAITS_HISTORY. */
48 PFS_ALIGNED bool flag_events_waits_history = false;
49 /** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */
50 PFS_ALIGNED bool flag_events_waits_history_long = false;
51 /** Consumer flag for the global instrumentation. */
52 PFS_ALIGNED bool flag_global_instrumentation = false;
53 /** Consumer flag for the per thread instrumentation. */
54 PFS_ALIGNED bool flag_thread_instrumentation = false;
55 
56 /** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */
57 PFS_ALIGNED bool events_waits_history_long_full = false;
58 /** Index in EVENTS_WAITS_HISTORY_LONG circular buffer. */
59 PFS_ALIGNED PFS_cacheline_atomic_uint32 events_waits_history_long_index;
60 /** EVENTS_WAITS_HISTORY_LONG circular buffer. */
61 PFS_ALIGNED PFS_events_waits *events_waits_history_long_array = nullptr;
62 
63 /**
64   Initialize table EVENTS_WAITS_HISTORY_LONG.
65   @param events_waits_history_long_sizing       table sizing
66 */
init_events_waits_history_long(uint events_waits_history_long_sizing)67 int init_events_waits_history_long(uint events_waits_history_long_sizing) {
68   events_waits_history_long_size = events_waits_history_long_sizing;
69   events_waits_history_long_full = false;
70   events_waits_history_long_index.m_u32.store(0);
71 
72   if (events_waits_history_long_size == 0) {
73     return 0;
74   }
75 
76   events_waits_history_long_array = PFS_MALLOC_ARRAY(
77       &builtin_memory_waits_history_long, events_waits_history_long_size,
78       sizeof(PFS_events_waits), PFS_events_waits, 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   PFS_FREE_ARRAY(&builtin_memory_waits_history_long,
86                  events_waits_history_long_size, sizeof(PFS_events_waits),
87                  events_waits_history_long_array);
88   events_waits_history_long_array = nullptr;
89 }
90 
copy_events_waits(PFS_events_waits * dest,const PFS_events_waits * source)91 static inline void copy_events_waits(PFS_events_waits *dest,
92                                      const PFS_events_waits *source) {
93   memcpy(dest, source, sizeof(PFS_events_waits));
94 }
95 
96 /**
97   Insert a wait record in table EVENTS_WAITS_HISTORY.
98   @param thread             thread that executed the wait
99   @param wait               record to insert
100 */
insert_events_waits_history(PFS_thread * thread,PFS_events_waits * wait)101 void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait) {
102   if (unlikely(events_waits_history_per_thread == 0)) {
103     return;
104   }
105 
106   uint index = thread->m_waits_history_index;
107 
108   /*
109     A concurrent thread executing TRUNCATE TABLE EVENTS_WAITS_CURRENT
110     could alter the data that this thread is inserting,
111     causing a potential race condition.
112     We are not testing for this and insert a possibly empty record,
113     to make this thread (the writer) faster.
114     This is ok, the readers of m_waits_history will filter this out.
115   */
116   copy_events_waits(&thread->m_waits_history[index], wait);
117 
118   index++;
119   if (index >= events_waits_history_per_thread) {
120     index = 0;
121     thread->m_waits_history_full = true;
122   }
123   thread->m_waits_history_index = index;
124 }
125 
126 /**
127   Insert a wait record in table EVENTS_WAITS_HISTORY_LONG.
128   @param wait               record to insert
129 */
insert_events_waits_history_long(PFS_events_waits * wait)130 void insert_events_waits_history_long(PFS_events_waits *wait) {
131   if (unlikely(events_waits_history_long_size == 0)) {
132     return;
133   }
134 
135   uint index = events_waits_history_long_index.m_u32++;
136 
137   index = index % events_waits_history_long_size;
138   if (index == 0) {
139     events_waits_history_long_full = true;
140   }
141 
142   /* See related comment in insert_events_waits_history. */
143   copy_events_waits(&events_waits_history_long_array[index], wait);
144 }
145 
fct_reset_events_waits_current(PFS_thread * pfs_thread)146 static void fct_reset_events_waits_current(PFS_thread *pfs_thread) {
147   PFS_events_waits *pfs_wait = pfs_thread->m_events_waits_stack;
148   PFS_events_waits *pfs_wait_last = pfs_wait + WAIT_STACK_SIZE;
149 
150   for (; pfs_wait < pfs_wait_last; pfs_wait++) {
151     pfs_wait->m_wait_class = NO_WAIT_CLASS;
152   }
153 }
154 
155 /** Reset table EVENTS_WAITS_CURRENT data. */
reset_events_waits_current(void)156 void reset_events_waits_current(void) {
157   global_thread_container.apply_all(fct_reset_events_waits_current);
158 }
159 
fct_reset_events_waits_history(PFS_thread * pfs_thread)160 static void fct_reset_events_waits_history(PFS_thread *pfs_thread) {
161   PFS_events_waits *wait = pfs_thread->m_waits_history;
162   PFS_events_waits *wait_last = wait + events_waits_history_per_thread;
163 
164   pfs_thread->m_waits_history_index = 0;
165   pfs_thread->m_waits_history_full = false;
166   for (; wait < wait_last; wait++) {
167     wait->m_wait_class = NO_WAIT_CLASS;
168   }
169 }
170 
171 /** Reset table EVENTS_WAITS_HISTORY data. */
reset_events_waits_history(void)172 void reset_events_waits_history(void) {
173   global_thread_container.apply_all(fct_reset_events_waits_history);
174 }
175 
176 /** Reset table EVENTS_WAITS_HISTORY_LONG data. */
reset_events_waits_history_long(void)177 void reset_events_waits_history_long(void) {
178   events_waits_history_long_index.m_u32.store(0);
179   events_waits_history_long_full = false;
180 
181   PFS_events_waits *wait = events_waits_history_long_array;
182   PFS_events_waits *wait_last = wait + events_waits_history_long_size;
183   for (; wait < wait_last; wait++) {
184     wait->m_wait_class = NO_WAIT_CLASS;
185   }
186 }
187 
fct_reset_events_waits_by_thread(PFS_thread * thread)188 static void fct_reset_events_waits_by_thread(PFS_thread *thread) {
189   PFS_account *account = sanitize_account(thread->m_account);
190   PFS_user *user = sanitize_user(thread->m_user);
191   PFS_host *host = sanitize_host(thread->m_host);
192   aggregate_thread_waits(thread, account, user, host);
193 }
194 
195 /** Reset table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
reset_events_waits_by_thread()196 void reset_events_waits_by_thread() {
197   global_thread_container.apply(fct_reset_events_waits_by_thread);
198 }
199 
fct_reset_events_waits_by_account(PFS_account * pfs)200 static void fct_reset_events_waits_by_account(PFS_account *pfs) {
201   PFS_user *user = sanitize_user(pfs->m_user);
202   PFS_host *host = sanitize_host(pfs->m_host);
203   pfs->aggregate_waits(user, host);
204 }
205 
206 /** Reset table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
reset_events_waits_by_account()207 void reset_events_waits_by_account() {
208   global_account_container.apply(fct_reset_events_waits_by_account);
209 }
210 
fct_reset_events_waits_by_user(PFS_user * pfs)211 static void fct_reset_events_waits_by_user(PFS_user *pfs) {
212   pfs->aggregate_waits();
213 }
214 
215 /** Reset table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
reset_events_waits_by_user()216 void reset_events_waits_by_user() {
217   global_user_container.apply(fct_reset_events_waits_by_user);
218 }
219 
fct_reset_events_waits_by_host(PFS_host * pfs)220 static void fct_reset_events_waits_by_host(PFS_host *pfs) {
221   pfs->aggregate_waits();
222 }
223 
224 /** Reset table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
reset_events_waits_by_host()225 void reset_events_waits_by_host() {
226   global_host_container.apply(fct_reset_events_waits_by_host);
227 }
228 
fct_reset_table_waits_by_table(PFS_table_share * pfs)229 static void fct_reset_table_waits_by_table(PFS_table_share *pfs) {
230   pfs->aggregate();
231 }
232 
reset_table_waits_by_table()233 void reset_table_waits_by_table() {
234   global_table_share_container.apply(fct_reset_table_waits_by_table);
235 }
236 
fct_reset_table_io_waits_by_table(PFS_table_share * pfs)237 static void fct_reset_table_io_waits_by_table(PFS_table_share *pfs) {
238   pfs->aggregate_io();
239 }
240 
reset_table_io_waits_by_table()241 void reset_table_io_waits_by_table() {
242   global_table_share_container.apply(fct_reset_table_io_waits_by_table);
243 }
244 
fct_reset_table_lock_waits_by_table(PFS_table_share * pfs)245 static void fct_reset_table_lock_waits_by_table(PFS_table_share *pfs) {
246   pfs->aggregate_lock();
247 }
248 
reset_table_lock_waits_by_table()249 void reset_table_lock_waits_by_table() {
250   global_table_share_container.apply(fct_reset_table_lock_waits_by_table);
251 }
252 
fct_reset_table_waits_by_table_handle(PFS_table * pfs)253 static void fct_reset_table_waits_by_table_handle(PFS_table *pfs) {
254   pfs->sanitized_aggregate();
255 }
256 
reset_table_waits_by_table_handle()257 void reset_table_waits_by_table_handle() {
258   global_table_container.apply(fct_reset_table_waits_by_table_handle);
259 }
260 
fct_reset_table_io_waits_by_table_handle(PFS_table * pfs)261 static void fct_reset_table_io_waits_by_table_handle(PFS_table *pfs) {
262   pfs->sanitized_aggregate_io();
263 }
264 
reset_table_io_waits_by_table_handle()265 void reset_table_io_waits_by_table_handle() {
266   global_table_container.apply(fct_reset_table_io_waits_by_table_handle);
267 }
268 
fct_reset_table_lock_waits_by_table_handle(PFS_table * pfs)269 static void fct_reset_table_lock_waits_by_table_handle(PFS_table *pfs) {
270   pfs->sanitized_aggregate_lock();
271 }
272 
reset_table_lock_waits_by_table_handle()273 void reset_table_lock_waits_by_table_handle() {
274   global_table_container.apply(fct_reset_table_lock_waits_by_table_handle);
275 }
276