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