1 /* Copyright (c) 2010, 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_statements.cc
25 Events statements 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_account.h"
34 #include "pfs_host.h"
35 #include "pfs_user.h"
36 #include "pfs_events_statements.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 size_t events_statements_history_long_size= 0;
43 /** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */
44 PFS_ALIGNED bool flag_events_statements_current= false;
45 /** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */
46 PFS_ALIGNED bool flag_events_statements_history= false;
47 /** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */
48 PFS_ALIGNED bool flag_events_statements_history_long= false;
49
50 /** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */
51 PFS_ALIGNED bool events_statements_history_long_full= false;
52 /** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
53 PFS_ALIGNED PFS_cacheline_uint32 events_statements_history_long_index;
54 /** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
55 PFS_ALIGNED PFS_events_statements *events_statements_history_long_array= NULL;
56 static unsigned char *h_long_stmts_digest_token_array= NULL;
57 static char *h_long_stmts_text_array= NULL;
58
59 /**
60 Initialize table EVENTS_STATEMENTS_HISTORY_LONG.
61 @param events_statements_history_long_sizing table sizing
62 */
init_events_statements_history_long(size_t events_statements_history_long_sizing)63 int init_events_statements_history_long(size_t events_statements_history_long_sizing)
64 {
65 events_statements_history_long_size= events_statements_history_long_sizing;
66 events_statements_history_long_full= false;
67 PFS_atomic::store_u32(&events_statements_history_long_index.m_u32, 0);
68
69 if (events_statements_history_long_size == 0)
70 return 0;
71
72 events_statements_history_long_array=
73 PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long,
74 events_statements_history_long_size, sizeof(PFS_events_statements),
75 PFS_events_statements, MYF(MY_ZEROFILL));
76
77 if (events_statements_history_long_array == NULL)
78 {
79 cleanup_events_statements_history_long();
80 return 1;
81 }
82
83 if (pfs_max_digest_length > 0)
84 {
85 /* Size of each digest text array. */
86 size_t digest_text_size= pfs_max_digest_length * sizeof(unsigned char);
87
88 h_long_stmts_digest_token_array=
89 PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long_tokens,
90 events_statements_history_long_size, digest_text_size,
91 unsigned char, MYF(MY_ZEROFILL));
92
93 if (h_long_stmts_digest_token_array == NULL)
94 {
95 cleanup_events_statements_history_long();
96 return 1;
97 }
98 }
99
100 if (pfs_max_sqltext > 0)
101 {
102 /* Size of each sql text array. */
103 size_t sqltext_size= pfs_max_sqltext * sizeof(char);
104
105 h_long_stmts_text_array=
106 PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long_sqltext,
107 events_statements_history_long_size, sqltext_size,
108 char, MYF(MY_ZEROFILL));
109
110 if (h_long_stmts_text_array == NULL)
111 {
112 cleanup_events_statements_history_long();
113 return 1;
114 }
115 }
116
117 for (size_t index= 0; index < events_statements_history_long_size; index++)
118 {
119 events_statements_history_long_array[index].m_digest_storage.reset(h_long_stmts_digest_token_array
120 + index * pfs_max_digest_length, pfs_max_digest_length);
121 events_statements_history_long_array[index].m_sqltext= h_long_stmts_text_array + index * pfs_max_sqltext;
122 }
123
124 return 0;
125 }
126
127 /** Cleanup table EVENTS_STATEMENTS_HISTORY_LONG. */
cleanup_events_statements_history_long(void)128 void cleanup_events_statements_history_long(void)
129 {
130 PFS_FREE_ARRAY(& builtin_memory_statements_history_long,
131 events_statements_history_long_size,
132 sizeof(PFS_events_statements),
133 events_statements_history_long_array);
134
135 PFS_FREE_ARRAY(& builtin_memory_statements_history_long_tokens,
136 events_statements_history_long_size,
137 (pfs_max_digest_length * sizeof(unsigned char)),
138 h_long_stmts_digest_token_array);
139
140 PFS_FREE_ARRAY(& builtin_memory_statements_history_long_sqltext,
141 events_statements_history_long_size,
142 (pfs_max_sqltext * sizeof(char)),
143 h_long_stmts_text_array);
144
145 events_statements_history_long_array= NULL;
146 h_long_stmts_digest_token_array= NULL;
147 h_long_stmts_text_array= NULL;
148 }
149
copy_events_statements(PFS_events_statements * dest,const PFS_events_statements * source)150 static inline void copy_events_statements(PFS_events_statements *dest,
151 const PFS_events_statements *source)
152 {
153 /* Copy all attributes except SQL TEXT and DIGEST */
154 memcpy(dest, source, my_offsetof(PFS_events_statements, m_sqltext));
155
156 /* Copy SQL TEXT */
157 int sqltext_length= source->m_sqltext_length;
158
159 if (sqltext_length > 0)
160 {
161 memcpy(dest->m_sqltext, source->m_sqltext, sqltext_length);
162 dest->m_sqltext_length= sqltext_length;
163 }
164 else
165 {
166 dest->m_sqltext_length= 0;
167 }
168
169 /* Copy DIGEST */
170 dest->m_digest_storage.copy(& source->m_digest_storage);
171 }
172
173 /**
174 Insert a statement record in table EVENTS_STATEMENTS_HISTORY.
175 @param thread thread that executed the wait
176 @param statement record to insert
177 */
insert_events_statements_history(PFS_thread * thread,PFS_events_statements * statement)178 void insert_events_statements_history(PFS_thread *thread, PFS_events_statements *statement)
179 {
180 if (unlikely(events_statements_history_per_thread == 0))
181 return;
182
183 assert(thread->m_statements_history != NULL);
184
185 uint index= thread->m_statements_history_index;
186
187 /*
188 A concurrent thread executing TRUNCATE TABLE EVENTS_STATEMENTS_CURRENT
189 could alter the data that this thread is inserting,
190 causing a potential race condition.
191 We are not testing for this and insert a possibly empty record,
192 to make this thread (the writer) faster.
193 This is ok, the readers of m_statements_history will filter this out.
194 */
195 copy_events_statements(&thread->m_statements_history[index], statement);
196
197 index++;
198 if (index >= events_statements_history_per_thread)
199 {
200 index= 0;
201 thread->m_statements_history_full= true;
202 }
203 thread->m_statements_history_index= index;
204 }
205
206 /**
207 Insert a statement record in table EVENTS_STATEMENTS_HISTORY_LONG.
208 @param statement record to insert
209 */
insert_events_statements_history_long(PFS_events_statements * statement)210 void insert_events_statements_history_long(PFS_events_statements *statement)
211 {
212 if (unlikely(events_statements_history_long_size == 0))
213 return ;
214
215 assert(events_statements_history_long_array != NULL);
216
217 uint index= PFS_atomic::add_u32(&events_statements_history_long_index.m_u32, 1);
218
219 index= index % events_statements_history_long_size;
220 if (index == 0)
221 events_statements_history_long_full= true;
222
223 /* See related comment in insert_events_statements_history. */
224 copy_events_statements(&events_statements_history_long_array[index], statement);
225 }
226
fct_reset_events_statements_current(PFS_thread * pfs_thread)227 static void fct_reset_events_statements_current(PFS_thread *pfs_thread)
228 {
229 PFS_events_statements *pfs_stmt= & pfs_thread->m_statement_stack[0];
230 PFS_events_statements *pfs_stmt_last= pfs_stmt + statement_stack_max;
231
232 for ( ; pfs_stmt < pfs_stmt_last; pfs_stmt++)
233 pfs_stmt->m_class= NULL;
234 }
235
236 /** Reset table EVENTS_STATEMENTS_CURRENT data. */
reset_events_statements_current(void)237 void reset_events_statements_current(void)
238 {
239 global_thread_container.apply_all(fct_reset_events_statements_current);
240 }
241
fct_reset_events_statements_history(PFS_thread * pfs_thread)242 static void fct_reset_events_statements_history(PFS_thread *pfs_thread)
243 {
244 PFS_events_statements *pfs= pfs_thread->m_statements_history;
245 PFS_events_statements *pfs_last= pfs + events_statements_history_per_thread;
246
247 pfs_thread->m_statements_history_index= 0;
248 pfs_thread->m_statements_history_full= false;
249 for ( ; pfs < pfs_last; pfs++)
250 pfs->m_class= NULL;
251 }
252
253 /** Reset table EVENTS_STATEMENTS_HISTORY data. */
reset_events_statements_history(void)254 void reset_events_statements_history(void)
255 {
256 global_thread_container.apply_all(fct_reset_events_statements_history);
257 }
258
259 /** Reset table EVENTS_STATEMENTS_HISTORY_LONG data. */
reset_events_statements_history_long(void)260 void reset_events_statements_history_long(void)
261 {
262 PFS_atomic::store_u32(&events_statements_history_long_index.m_u32, 0);
263 events_statements_history_long_full= false;
264
265 PFS_events_statements *pfs= events_statements_history_long_array;
266 PFS_events_statements *pfs_last= pfs + events_statements_history_long_size;
267 for ( ; pfs < pfs_last; pfs++)
268 pfs->m_class= NULL;
269 }
270
fct_reset_events_statements_by_thread(PFS_thread * thread)271 static void fct_reset_events_statements_by_thread(PFS_thread *thread)
272 {
273 PFS_account *account= sanitize_account(thread->m_account);
274 PFS_user *user= sanitize_user(thread->m_user);
275 PFS_host *host= sanitize_host(thread->m_host);
276 aggregate_thread_statements(thread, account, user, host);
277 }
278
279 /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
reset_events_statements_by_thread()280 void reset_events_statements_by_thread()
281 {
282 global_thread_container.apply(fct_reset_events_statements_by_thread);
283 }
284
fct_reset_events_statements_by_account(PFS_account * pfs)285 static void fct_reset_events_statements_by_account(PFS_account *pfs)
286 {
287 PFS_user *user= sanitize_user(pfs->m_user);
288 PFS_host *host= sanitize_host(pfs->m_host);
289 pfs->aggregate_statements(user, host);
290 }
291
292 /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
reset_events_statements_by_account()293 void reset_events_statements_by_account()
294 {
295 global_account_container.apply(fct_reset_events_statements_by_account);
296 }
297
fct_reset_events_statements_by_user(PFS_user * pfs)298 static void fct_reset_events_statements_by_user(PFS_user *pfs)
299 {
300 pfs->aggregate_statements();
301 }
302
303 /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
reset_events_statements_by_user()304 void reset_events_statements_by_user()
305 {
306 global_user_container.apply(fct_reset_events_statements_by_user);
307 }
308
fct_reset_events_statements_by_host(PFS_host * pfs)309 static void fct_reset_events_statements_by_host(PFS_host *pfs)
310 {
311 pfs->aggregate_statements();
312 }
313
314 /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
reset_events_statements_by_host()315 void reset_events_statements_by_host()
316 {
317 global_host_container.apply(fct_reset_events_statements_by_host);
318 }
319
320 /** Reset table EVENTS_STATEMENTS_GLOBAL_BY_EVENT_NAME data. */
reset_events_statements_global()321 void reset_events_statements_global()
322 {
323 PFS_statement_stat *stat= global_instr_class_statements_array;
324 PFS_statement_stat *stat_last= global_instr_class_statements_array + statement_class_max;
325
326 for ( ; stat < stat_last; stat++)
327 stat->reset();
328 }
329
330