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
33size_t events_statements_history_long_size= 0;
34/** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */
35bool flag_events_statements_current= false;
36/** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */
37bool flag_events_statements_history= false;
38/** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */
39bool flag_events_statements_history_long= false;
40
41/** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */
42bool events_statements_history_long_full= false;
43/** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
44volatile uint32 events_statements_history_long_index= 0;
45/** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
46PFS_events_statements *events_statements_history_long_array= NULL;
47static 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*/
53int 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. */
97void 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
105static 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*/
120void 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*/
152void 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. */
170void 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. */
186void 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. */
204void 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. */
216void 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. */
237void 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. */
256void 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. */
269void 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. */
282void 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