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_stages.cc
25   Events stages 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_stages.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_stages_history_long_size= 0;
43 /** Consumer flag for table EVENTS_STAGES_CURRENT. */
44 PFS_ALIGNED bool flag_events_stages_current= false;
45 /** Consumer flag for table EVENTS_STAGES_HISTORY. */
46 PFS_ALIGNED bool flag_events_stages_history= false;
47 /** Consumer flag for table EVENTS_STAGES_HISTORY_LONG. */
48 PFS_ALIGNED bool flag_events_stages_history_long= false;
49 
50 /** True if EVENTS_STAGES_HISTORY_LONG circular buffer is full. */
51 PFS_ALIGNED bool events_stages_history_long_full= false;
52 /** Index in EVENTS_STAGES_HISTORY_LONG circular buffer. */
53 PFS_ALIGNED PFS_cacheline_uint32 events_stages_history_long_index;
54 /** EVENTS_STAGES_HISTORY_LONG circular buffer. */
55 PFS_ALIGNED PFS_events_stages *events_stages_history_long_array= NULL;
56 
57 /**
58   Initialize table EVENTS_STAGES_HISTORY_LONG.
59   @param events_stages_history_long_sizing       table sizing
60 */
init_events_stages_history_long(uint events_stages_history_long_sizing)61 int init_events_stages_history_long(uint events_stages_history_long_sizing)
62 {
63   events_stages_history_long_size= events_stages_history_long_sizing;
64   events_stages_history_long_full= false;
65   PFS_atomic::store_u32(&events_stages_history_long_index.m_u32, 0);
66 
67   if (events_stages_history_long_size == 0)
68     return 0;
69 
70   events_stages_history_long_array=
71     PFS_MALLOC_ARRAY(& builtin_memory_stages_history_long,
72                      events_stages_history_long_size,
73                      sizeof(PFS_events_stages), PFS_events_stages,
74                      MYF(MY_ZEROFILL));
75 
76   return (events_stages_history_long_array ? 0 : 1);
77 }
78 
79 /** Cleanup table EVENTS_STAGES_HISTORY_LONG. */
cleanup_events_stages_history_long(void)80 void cleanup_events_stages_history_long(void)
81 {
82   PFS_FREE_ARRAY(& builtin_memory_stages_history_long,
83                  events_stages_history_long_size, sizeof(PFS_events_stages),
84                  events_stages_history_long_array);
85   events_stages_history_long_array= NULL;
86 }
87 
copy_events_stages(PFS_events_stages * dest,const PFS_events_stages * source)88 static inline void copy_events_stages(PFS_events_stages *dest,
89                                       const PFS_events_stages *source)
90 {
91   memcpy(dest, source, sizeof(PFS_events_stages));
92 }
93 
94 /**
95   Insert a stage record in table EVENTS_STAGES_HISTORY.
96   @param thread             thread that executed the wait
97   @param stage              record to insert
98 */
insert_events_stages_history(PFS_thread * thread,PFS_events_stages * stage)99 void insert_events_stages_history(PFS_thread *thread, PFS_events_stages *stage)
100 {
101   if (unlikely(events_stages_history_per_thread == 0))
102     return;
103 
104   assert(thread->m_stages_history != NULL);
105 
106   uint index= thread->m_stages_history_index;
107 
108   /*
109     A concurrent thread executing TRUNCATE TABLE EVENTS_STAGES_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_stages_history will filter this out.
115   */
116   copy_events_stages(&thread->m_stages_history[index], stage);
117 
118   index++;
119   if (index >= events_stages_history_per_thread)
120   {
121     index= 0;
122     thread->m_stages_history_full= true;
123   }
124   thread->m_stages_history_index= index;
125 }
126 
127 /**
128   Insert a stage record in table EVENTS_STAGES_HISTORY_LONG.
129   @param stage              record to insert
130 */
insert_events_stages_history_long(PFS_events_stages * stage)131 void insert_events_stages_history_long(PFS_events_stages *stage)
132 {
133   if (unlikely(events_stages_history_long_size == 0))
134     return;
135 
136   assert(events_stages_history_long_array != NULL);
137 
138   uint index= PFS_atomic::add_u32(&events_stages_history_long_index.m_u32, 1);
139 
140   index= index % events_stages_history_long_size;
141   if (index == 0)
142     events_stages_history_long_full= true;
143 
144   /* See related comment in insert_events_stages_history. */
145   copy_events_stages(&events_stages_history_long_array[index], stage);
146 }
147 
fct_reset_events_stages_current(PFS_thread * pfs)148 static void fct_reset_events_stages_current(PFS_thread *pfs)
149 {
150   pfs->m_stage_current.m_class= NULL;
151 }
152 
153 /** Reset table EVENTS_STAGES_CURRENT data. */
reset_events_stages_current(void)154 void reset_events_stages_current(void)
155 {
156   global_thread_container.apply_all(fct_reset_events_stages_current);
157 }
158 
fct_reset_events_stages_history(PFS_thread * pfs_thread)159 static void fct_reset_events_stages_history(PFS_thread *pfs_thread)
160 {
161   PFS_events_stages *pfs= pfs_thread->m_stages_history;
162   PFS_events_stages *pfs_last= pfs + events_stages_history_per_thread;
163 
164   pfs_thread->m_stages_history_index= 0;
165   pfs_thread->m_stages_history_full= false;
166   for ( ; pfs < pfs_last; pfs++)
167     pfs->m_class= NULL;
168 }
169 
170 /** Reset table EVENTS_STAGES_HISTORY data. */
reset_events_stages_history(void)171 void reset_events_stages_history(void)
172 {
173   global_thread_container.apply_all(fct_reset_events_stages_history);
174 }
175 
176 /** Reset table EVENTS_STAGES_HISTORY_LONG data. */
reset_events_stages_history_long(void)177 void reset_events_stages_history_long(void)
178 {
179   PFS_atomic::store_u32(&events_stages_history_long_index.m_u32, 0);
180   events_stages_history_long_full= false;
181 
182   PFS_events_stages *pfs= events_stages_history_long_array;
183   PFS_events_stages *pfs_last= pfs + events_stages_history_long_size;
184   for ( ; pfs < pfs_last; pfs++)
185     pfs->m_class= NULL;
186 }
187 
fct_reset_events_stages_by_thread(PFS_thread * thread)188 static void fct_reset_events_stages_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_stages(thread, account, user, host);
194 }
195 
196 /** Reset table EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
reset_events_stages_by_thread()197 void reset_events_stages_by_thread()
198 {
199   global_thread_container.apply(fct_reset_events_stages_by_thread);
200 }
201 
fct_reset_events_stages_by_account(PFS_account * pfs)202 static void fct_reset_events_stages_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_stages(user, host);
207 }
208 
209 /** Reset table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
reset_events_stages_by_account()210 void reset_events_stages_by_account()
211 {
212   global_account_container.apply(fct_reset_events_stages_by_account);
213 }
214 
fct_reset_events_stages_by_user(PFS_user * pfs)215 static void fct_reset_events_stages_by_user(PFS_user *pfs)
216 {
217   pfs->aggregate_stages();
218 }
219 
220 /** Reset table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME data. */
reset_events_stages_by_user()221 void reset_events_stages_by_user()
222 {
223   global_user_container.apply(fct_reset_events_stages_by_user);
224 }
225 
fct_reset_events_stages_by_host(PFS_host * pfs)226 static void fct_reset_events_stages_by_host(PFS_host *pfs)
227 {
228   pfs->aggregate_stages();
229 }
230 
231 /** Reset table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
reset_events_stages_by_host()232 void reset_events_stages_by_host()
233 {
234   global_host_container.apply(fct_reset_events_stages_by_host);
235 }
236 
237 /** Reset table EVENTS_STAGES_GLOBAL_BY_EVENT_NAME data. */
reset_events_stages_global()238 void reset_events_stages_global()
239 {
240   PFS_stage_stat *stat= global_instr_class_stages_array;
241   PFS_stage_stat *stat_last= global_instr_class_stages_array + stage_class_max;
242 
243   for ( ; stat < stat_last; stat++)
244     stat->reset();
245 }
246 
247