1 /* Copyright (c) 2013, 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_transactions.cc
25 Events transactions 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_transactions.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 ulong events_transactions_history_long_size= 0;
43 /** Consumer flag for table EVENTS_TRANSACTIONS_CURRENT. */
44 PFS_ALIGNED bool flag_events_transactions_current= false;
45 /** Consumer flag for table EVENTS_TRANSACTIONS_HISTORY. */
46 PFS_ALIGNED bool flag_events_transactions_history= false;
47 /** Consumer flag for table EVENTS_TRANSACTIONS_HISTORY_LONG. */
48 PFS_ALIGNED bool flag_events_transactions_history_long= false;
49
50 /** True if EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer is full. */
51 PFS_ALIGNED bool events_transactions_history_long_full= false;
52 /** Index in EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer. */
53 PFS_ALIGNED PFS_cacheline_uint32 events_transactions_history_long_index;
54 /** EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer. */
55 PFS_ALIGNED PFS_events_transactions *events_transactions_history_long_array= NULL;
56
57 /**
58 Initialize table EVENTS_TRANSACTIONS_HISTORY_LONG.
59 @param events_transactions_history_long_sizing table sizing
60 */
init_events_transactions_history_long(uint events_transactions_history_long_sizing)61 int init_events_transactions_history_long(uint events_transactions_history_long_sizing)
62 {
63 events_transactions_history_long_size= events_transactions_history_long_sizing;
64 events_transactions_history_long_full= false;
65 PFS_atomic::store_u32(&events_transactions_history_long_index.m_u32, 0);
66
67 if (events_transactions_history_long_size == 0)
68 return 0;
69
70 events_transactions_history_long_array=
71 PFS_MALLOC_ARRAY(& builtin_memory_transactions_history_long,
72 events_transactions_history_long_size,
73 sizeof(PFS_events_transactions), PFS_events_transactions,
74 MYF(MY_ZEROFILL));
75
76 return (events_transactions_history_long_array ? 0 : 1);
77 }
78
79 /** Cleanup table EVENTS_TRANSACTIONS_HISTORY_LONG. */
cleanup_events_transactions_history_long(void)80 void cleanup_events_transactions_history_long(void)
81 {
82 PFS_FREE_ARRAY(& builtin_memory_transactions_history_long,
83 events_transactions_history_long_size, sizeof(PFS_events_transactions),
84 events_transactions_history_long_array);
85 events_transactions_history_long_array= NULL;
86 }
87
copy_events_transactions(PFS_events_transactions * dest,const PFS_events_transactions * source)88 static inline void copy_events_transactions(PFS_events_transactions *dest,
89 const PFS_events_transactions *source)
90 {
91 memcpy(dest, source, sizeof(PFS_events_transactions));
92 }
93
94 /**
95 Insert a transaction record in table EVENTS_TRANSACTIONS_HISTORY.
96 @param thread thread that executed the wait
97 @param transaction record to insert
98 */
insert_events_transactions_history(PFS_thread * thread,PFS_events_transactions * transaction)99 void insert_events_transactions_history(PFS_thread *thread, PFS_events_transactions *transaction)
100 {
101 if (unlikely(events_transactions_history_per_thread == 0))
102 return;
103
104 assert(thread->m_transactions_history != NULL);
105
106 uint index= thread->m_transactions_history_index;
107
108 /*
109 A concurrent thread executing TRUNCATE TABLE EVENTS_TRANSACTIONS_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_transactions_history will filter this out.
115 */
116 copy_events_transactions(&thread->m_transactions_history[index], transaction);
117
118 index++;
119 if (index >= events_transactions_history_per_thread)
120 {
121 index= 0;
122 thread->m_transactions_history_full= true;
123 }
124 thread->m_transactions_history_index= index;
125 }
126
127 /**
128 Insert a transaction record in table EVENTS_TRANSACTIONS_HISTORY_LONG.
129 @param transaction record to insert
130 */
insert_events_transactions_history_long(PFS_events_transactions * transaction)131 void insert_events_transactions_history_long(PFS_events_transactions *transaction)
132 {
133 if (unlikely(events_transactions_history_long_size == 0))
134 return ;
135
136 assert(events_transactions_history_long_array != NULL);
137
138 uint index= PFS_atomic::add_u32(&events_transactions_history_long_index.m_u32, 1);
139
140 index= index % events_transactions_history_long_size;
141 if (index == 0)
142 events_transactions_history_long_full= true;
143
144 /* See related comment in insert_events_transactions_history. */
145 copy_events_transactions(&events_transactions_history_long_array[index], transaction);
146 }
147
fct_reset_events_transactions_current(PFS_thread * pfs)148 static void fct_reset_events_transactions_current(PFS_thread *pfs)
149 {
150 pfs->m_transaction_current.m_class= NULL;
151 }
152
153 /** Reset table EVENTS_TRANSACTIONS_CURRENT data. */
reset_events_transactions_current(void)154 void reset_events_transactions_current(void)
155 {
156 global_thread_container.apply_all(fct_reset_events_transactions_current);
157 }
158
fct_reset_events_transactions_history(PFS_thread * pfs_thread)159 static void fct_reset_events_transactions_history(PFS_thread *pfs_thread)
160 {
161 PFS_events_transactions *pfs= pfs_thread->m_transactions_history;
162 PFS_events_transactions *pfs_last= pfs + events_transactions_history_per_thread;
163
164 pfs_thread->m_transactions_history_index= 0;
165 pfs_thread->m_transactions_history_full= false;
166 for ( ; pfs < pfs_last; pfs++)
167 pfs->m_class= NULL;
168 }
169
170 /** Reset table EVENTS_TRANSACTIONS_HISTORY data. */
reset_events_transactions_history(void)171 void reset_events_transactions_history(void)
172 {
173 global_thread_container.apply_all(fct_reset_events_transactions_history);
174 }
175
176 /** Reset table EVENTS_TRANSACTIONS_HISTORY_LONG data. */
reset_events_transactions_history_long(void)177 void reset_events_transactions_history_long(void)
178 {
179 PFS_atomic::store_u32(&events_transactions_history_long_index.m_u32, 0);
180 events_transactions_history_long_full= false;
181
182 PFS_events_transactions *pfs= events_transactions_history_long_array;
183 PFS_events_transactions *pfs_last= pfs + events_transactions_history_long_size;
184 for ( ; pfs < pfs_last; pfs++)
185 pfs->m_class= NULL;
186 }
187
fct_reset_events_transactions_by_thread(PFS_thread * thread)188 static void fct_reset_events_transactions_by_thread(PFS_thread *thread)
189 {
190 PFS_account *account= sanitize_account(thread->m_account);
191 PFS_user *user= sanitize_user(thread->m_user);
192 PFS_host *host= sanitize_host(thread->m_host);
193 aggregate_thread_transactions(thread, account, user, host);
194 }
195
196 /** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
reset_events_transactions_by_thread()197 void reset_events_transactions_by_thread()
198 {
199 global_thread_container.apply(fct_reset_events_transactions_by_thread);
200 }
201
fct_reset_events_transactions_by_account(PFS_account * pfs)202 static void fct_reset_events_transactions_by_account(PFS_account *pfs)
203 {
204 PFS_user *user= sanitize_user(pfs->m_user);
205 PFS_host *host= sanitize_host(pfs->m_host);
206 pfs->aggregate_transactions(user, host);
207 }
208
209 /** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
reset_events_transactions_by_account()210 void reset_events_transactions_by_account()
211 {
212 global_account_container.apply(fct_reset_events_transactions_by_account);
213 }
214
fct_reset_events_transactions_by_user(PFS_user * pfs)215 static void fct_reset_events_transactions_by_user(PFS_user *pfs)
216 {
217 pfs->aggregate_transactions();
218 }
219
220 /** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
reset_events_transactions_by_user()221 void reset_events_transactions_by_user()
222 {
223 global_user_container.apply(fct_reset_events_transactions_by_user);
224 }
225
fct_reset_events_transactions_by_host(PFS_host * pfs)226 static void fct_reset_events_transactions_by_host(PFS_host *pfs)
227 {
228 pfs->aggregate_transactions();
229 }
230
231 /** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
reset_events_transactions_by_host()232 void reset_events_transactions_by_host()
233 {
234 global_host_container.apply(fct_reset_events_transactions_by_host);
235 }
236
237 /** Reset table EVENTS_TRANSACTIONS_GLOBAL_BY_EVENT_NAME data. */
reset_events_transactions_global()238 void reset_events_transactions_global()
239 {
240 global_transaction_stat.reset();
241 }
242
243 /**
244 Check if the XID consists of printable characters, ASCII 32 - 127.
245 @param xid XID structure
246 @param offset offset into XID.data[]
247 @param length number of bytes to process
248 @return true if all bytes are in printable range
249 */
xid_printable(PSI_xid * xid,size_t offset,size_t length)250 bool xid_printable(PSI_xid *xid, size_t offset, size_t length)
251 {
252 if (xid->is_null())
253 return false;
254
255 assert(offset + length <= MYSQL_XIDDATASIZE);
256
257 unsigned char *c= (unsigned char*)&xid->data + offset;
258
259 for (size_t i= 0; i < length; i++, c++)
260 {
261 if(*c < 32 || *c > 127)
262 return false;
263 }
264
265 return true;
266 }
267
268