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