1 | /* Copyright (c) 2010, 2015, 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 as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software Foundation, |
14 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ |
15 | |
16 | /** |
17 | @file storage/perfschema/pfs_events_statements.cc |
18 | Events statements data structures (implementation). |
19 | */ |
20 | |
21 | #include "my_global.h" |
22 | #include "my_sys.h" |
23 | #include "pfs_global.h" |
24 | #include "pfs_instr_class.h" |
25 | #include "pfs_instr.h" |
26 | #include "pfs_account.h" |
27 | #include "pfs_host.h" |
28 | #include "pfs_user.h" |
29 | #include "pfs_events_statements.h" |
30 | #include "pfs_atomic.h" |
31 | #include "m_string.h" |
32 | |
33 | size_t events_statements_history_long_size= 0; |
34 | /** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */ |
35 | bool flag_events_statements_current= false; |
36 | /** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */ |
37 | bool flag_events_statements_history= false; |
38 | /** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */ |
39 | bool flag_events_statements_history_long= false; |
40 | |
41 | /** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */ |
42 | bool events_statements_history_long_full= false; |
43 | /** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ |
44 | volatile uint32 events_statements_history_long_index= 0; |
45 | /** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ |
46 | PFS_events_statements *events_statements_history_long_array= NULL; |
47 | static unsigned char *h_long_stmts_digest_token_array= NULL; |
48 | |
49 | /** |
50 | Initialize table EVENTS_STATEMENTS_HISTORY_LONG. |
51 | @param events_statements_history_long_sizing table sizing |
52 | */ |
53 | int init_events_statements_history_long(size_t events_statements_history_long_sizing) |
54 | { |
55 | events_statements_history_long_size= events_statements_history_long_sizing; |
56 | events_statements_history_long_full= false; |
57 | PFS_atomic::store_u32(&events_statements_history_long_index, 0); |
58 | |
59 | if (events_statements_history_long_size == 0) |
60 | return 0; |
61 | |
62 | events_statements_history_long_array= |
63 | PFS_MALLOC_ARRAY(events_statements_history_long_size, sizeof(PFS_events_statements), |
64 | PFS_events_statements, MYF(MY_ZEROFILL)); |
65 | |
66 | if (events_statements_history_long_array == NULL) |
67 | { |
68 | cleanup_events_statements_history_long(); |
69 | return 1; |
70 | } |
71 | |
72 | if (pfs_max_digest_length > 0) |
73 | { |
74 | /* Size of each digest token array. */ |
75 | size_t digest_text_size= pfs_max_digest_length * sizeof(unsigned char); |
76 | |
77 | h_long_stmts_digest_token_array= |
78 | PFS_MALLOC_ARRAY(events_statements_history_long_size, digest_text_size, |
79 | unsigned char, MYF(MY_ZEROFILL)); |
80 | if (h_long_stmts_digest_token_array == NULL) |
81 | { |
82 | cleanup_events_statements_history_long(); |
83 | return 1; |
84 | } |
85 | } |
86 | |
87 | for (size_t index= 0; index < events_statements_history_long_size; index++) |
88 | { |
89 | events_statements_history_long_array[index].m_digest_storage.reset(h_long_stmts_digest_token_array |
90 | + index * pfs_max_digest_length, pfs_max_digest_length); |
91 | } |
92 | |
93 | return 0; |
94 | } |
95 | |
96 | /** Cleanup table EVENTS_STATEMENTS_HISTORY_LONG. */ |
97 | void cleanup_events_statements_history_long(void) |
98 | { |
99 | pfs_free(events_statements_history_long_array); |
100 | pfs_free(h_long_stmts_digest_token_array); |
101 | events_statements_history_long_array= NULL; |
102 | h_long_stmts_digest_token_array= NULL; |
103 | } |
104 | |
105 | static inline void copy_events_statements(PFS_events_statements *dest, |
106 | const PFS_events_statements *source) |
107 | { |
108 | /* Copy all attributes except DIGEST */ |
109 | memcpy(dest, source, my_offsetof(PFS_events_statements, m_digest_storage)); |
110 | |
111 | /* Copy DIGEST */ |
112 | dest->m_digest_storage.copy(& source->m_digest_storage); |
113 | } |
114 | |
115 | /** |
116 | Insert a statement record in table EVENTS_STATEMENTS_HISTORY. |
117 | @param thread thread that executed the wait |
118 | @param statement record to insert |
119 | */ |
120 | void insert_events_statements_history(PFS_thread *thread, PFS_events_statements *statement) |
121 | { |
122 | if (unlikely(events_statements_history_per_thread == 0)) |
123 | return; |
124 | |
125 | DBUG_ASSERT(thread->m_statements_history != NULL); |
126 | |
127 | uint index= thread->m_statements_history_index; |
128 | |
129 | /* |
130 | A concurrent thread executing TRUNCATE TABLE EVENTS_STATEMENTS_CURRENT |
131 | could alter the data that this thread is inserting, |
132 | causing a potential race condition. |
133 | We are not testing for this and insert a possibly empty record, |
134 | to make this thread (the writer) faster. |
135 | This is ok, the readers of m_statements_history will filter this out. |
136 | */ |
137 | copy_events_statements(&thread->m_statements_history[index], statement); |
138 | |
139 | index++; |
140 | if (index >= events_statements_history_per_thread) |
141 | { |
142 | index= 0; |
143 | thread->m_statements_history_full= true; |
144 | } |
145 | thread->m_statements_history_index= index; |
146 | } |
147 | |
148 | /** |
149 | Insert a statement record in table EVENTS_STATEMENTS_HISTORY_LONG. |
150 | @param statement record to insert |
151 | */ |
152 | void insert_events_statements_history_long(PFS_events_statements *statement) |
153 | { |
154 | if (unlikely(events_statements_history_long_size == 0)) |
155 | return ; |
156 | |
157 | DBUG_ASSERT(events_statements_history_long_array != NULL); |
158 | |
159 | uint index= PFS_atomic::add_u32(&events_statements_history_long_index, 1); |
160 | |
161 | index= index % events_statements_history_long_size; |
162 | if (index == 0) |
163 | events_statements_history_long_full= true; |
164 | |
165 | /* See related comment in insert_events_statements_history. */ |
166 | copy_events_statements(&events_statements_history_long_array[index], statement); |
167 | } |
168 | |
169 | /** Reset table EVENTS_STATEMENTS_CURRENT data. */ |
170 | void reset_events_statements_current(void) |
171 | { |
172 | PFS_thread *pfs_thread= thread_array; |
173 | PFS_thread *pfs_thread_last= thread_array + thread_max; |
174 | |
175 | for ( ; pfs_thread < pfs_thread_last; pfs_thread++) |
176 | { |
177 | PFS_events_statements *pfs_stmt= & pfs_thread->m_statement_stack[0]; |
178 | PFS_events_statements *pfs_stmt_last= pfs_stmt + statement_stack_max; |
179 | |
180 | for ( ; pfs_stmt < pfs_stmt_last; pfs_stmt++) |
181 | pfs_stmt->m_class= NULL; |
182 | } |
183 | } |
184 | |
185 | /** Reset table EVENTS_STATEMENTS_HISTORY data. */ |
186 | void reset_events_statements_history(void) |
187 | { |
188 | PFS_thread *pfs_thread= thread_array; |
189 | PFS_thread *pfs_thread_last= thread_array + thread_max; |
190 | |
191 | for ( ; pfs_thread < pfs_thread_last; pfs_thread++) |
192 | { |
193 | PFS_events_statements *pfs= pfs_thread->m_statements_history; |
194 | PFS_events_statements *pfs_last= pfs + events_statements_history_per_thread; |
195 | |
196 | pfs_thread->m_statements_history_index= 0; |
197 | pfs_thread->m_statements_history_full= false; |
198 | for ( ; pfs < pfs_last; pfs++) |
199 | pfs->m_class= NULL; |
200 | } |
201 | } |
202 | |
203 | /** Reset table EVENTS_STATEMENTS_HISTORY_LONG data. */ |
204 | void reset_events_statements_history_long(void) |
205 | { |
206 | PFS_atomic::store_u32(&events_statements_history_long_index, 0); |
207 | events_statements_history_long_full= false; |
208 | |
209 | PFS_events_statements *pfs= events_statements_history_long_array; |
210 | PFS_events_statements *pfs_last= pfs + events_statements_history_long_size; |
211 | for ( ; pfs < pfs_last; pfs++) |
212 | pfs->m_class= NULL; |
213 | } |
214 | |
215 | /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */ |
216 | void reset_events_statements_by_thread() |
217 | { |
218 | PFS_thread *thread= thread_array; |
219 | PFS_thread *thread_last= thread_array + thread_max; |
220 | PFS_account *account; |
221 | PFS_user *user; |
222 | PFS_host *host; |
223 | |
224 | for ( ; thread < thread_last; thread++) |
225 | { |
226 | if (thread->m_lock.is_populated()) |
227 | { |
228 | account= sanitize_account(thread->m_account); |
229 | user= sanitize_user(thread->m_user); |
230 | host= sanitize_host(thread->m_host); |
231 | aggregate_thread_statements(thread, account, user, host); |
232 | } |
233 | } |
234 | } |
235 | |
236 | /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */ |
237 | void reset_events_statements_by_account() |
238 | { |
239 | PFS_account *pfs= account_array; |
240 | PFS_account *pfs_last= account_array + account_max; |
241 | PFS_user *user; |
242 | PFS_host *host; |
243 | |
244 | for ( ; pfs < pfs_last; pfs++) |
245 | { |
246 | if (pfs->m_lock.is_populated()) |
247 | { |
248 | user= sanitize_user(pfs->m_user); |
249 | host= sanitize_host(pfs->m_host); |
250 | pfs->aggregate_statements(user, host); |
251 | } |
252 | } |
253 | } |
254 | |
255 | /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME data. */ |
256 | void reset_events_statements_by_user() |
257 | { |
258 | PFS_user *pfs= user_array; |
259 | PFS_user *pfs_last= user_array + user_max; |
260 | |
261 | for ( ; pfs < pfs_last; pfs++) |
262 | { |
263 | if (pfs->m_lock.is_populated()) |
264 | pfs->aggregate_statements(); |
265 | } |
266 | } |
267 | |
268 | /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */ |
269 | void reset_events_statements_by_host() |
270 | { |
271 | PFS_host *pfs= host_array; |
272 | PFS_host *pfs_last= host_array + host_max; |
273 | |
274 | for ( ; pfs < pfs_last; pfs++) |
275 | { |
276 | if (pfs->m_lock.is_populated()) |
277 | pfs->aggregate_statements(); |
278 | } |
279 | } |
280 | |
281 | /** Reset table EVENTS_STATEMENTS_GLOBAL_BY_EVENT_NAME data. */ |
282 | void reset_events_statements_global() |
283 | { |
284 | PFS_statement_stat *stat= global_instr_class_statements_array; |
285 | PFS_statement_stat *stat_last= global_instr_class_statements_array + statement_class_max; |
286 | |
287 | for ( ; stat < stat_last; stat++) |
288 | stat->reset(); |
289 | } |
290 | |
291 | |