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