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