1 /* Copyright (c) 2008, 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_server.cc
25 Private interface for the server (implementation).
26 */
27
28 #include "my_global.h"
29 #include "my_sys.h"
30 #include "mysys_err.h"
31 #include "pfs_server.h"
32 #include "pfs.h"
33 #include "pfs_global.h"
34 #include "pfs_instr_class.h"
35 #include "pfs_builtin_memory.h"
36 #include "pfs_instr.h"
37 #include "pfs_events_waits.h"
38 #include "pfs_events_stages.h"
39 #include "pfs_events_statements.h"
40 #include "pfs_events_transactions.h"
41 #include "pfs_timer.h"
42 #include "pfs_setup_actor.h"
43 #include "pfs_setup_object.h"
44 #include "pfs_host.h"
45 #include "pfs_user.h"
46 #include "pfs_account.h"
47 #include "pfs_defaults.h"
48 #include "pfs_digest.h"
49 #include "pfs_program.h"
50 #include "template_utils.h"
51 #include "pfs_prepared_stmt.h"
52
53 PFS_global_param pfs_param;
54
55 PFS_table_stat PFS_table_stat::g_reset_template;
56
57 C_MODE_START
58 static void destroy_pfs_thread(void *key);
59 C_MODE_END
60
61 static void cleanup_performance_schema(void);
62 void cleanup_instrument_config(void);
63
pre_initialize_performance_schema()64 void pre_initialize_performance_schema()
65 {
66 pfs_initialized= false;
67
68 init_all_builtin_memory_class();
69
70 PFS_table_stat::g_reset_template.reset();
71 global_idle_stat.reset();
72 global_table_io_stat.reset();
73 global_table_lock_stat.reset();
74
75 if (my_create_thread_local_key(&THR_PFS, destroy_pfs_thread))
76 return;
77 if (my_create_thread_local_key(&THR_PFS_VG, NULL)) // global_variables
78 return;
79 if (my_create_thread_local_key(&THR_PFS_SV, NULL)) // session_variables
80 return;
81 if (my_create_thread_local_key(&THR_PFS_VBT, NULL)) // variables_by_thread
82 return;
83 if (my_create_thread_local_key(&THR_PFS_SG, NULL)) // global_status
84 return;
85 if (my_create_thread_local_key(&THR_PFS_SS, NULL)) // session_status
86 return;
87 if (my_create_thread_local_key(&THR_PFS_SBT, NULL)) // status_by_thread
88 return;
89 if (my_create_thread_local_key(&THR_PFS_SBU, NULL)) // status_by_user
90 return;
91 if (my_create_thread_local_key(&THR_PFS_SBH, NULL)) // status_by_host
92 return;
93 if (my_create_thread_local_key(&THR_PFS_SBA, NULL)) // status_by_account
94 return;
95
96 THR_PFS_initialized= true;
97 }
98
99 struct PSI_bootstrap*
initialize_performance_schema(PFS_global_param * param)100 initialize_performance_schema(PFS_global_param *param)
101 {
102 if (!THR_PFS_initialized)
103 {
104 /* Pre-initialization failed. */
105 return NULL;
106 }
107
108 pfs_enabled= param->m_enabled;
109
110 pfs_automated_sizing(param);
111 init_timers();
112 init_event_name_sizing(param);
113 register_global_classes();
114
115 if (init_sync_class(param->m_mutex_class_sizing,
116 param->m_rwlock_class_sizing,
117 param->m_cond_class_sizing) ||
118 init_thread_class(param->m_thread_class_sizing) ||
119 init_table_share(param->m_table_share_sizing) ||
120 init_table_share_lock_stat(param->m_table_lock_stat_sizing) ||
121 init_table_share_index_stat(param->m_index_stat_sizing) ||
122 init_file_class(param->m_file_class_sizing) ||
123 init_stage_class(param->m_stage_class_sizing) ||
124 init_statement_class(param->m_statement_class_sizing) ||
125 init_socket_class(param->m_socket_class_sizing) ||
126 init_memory_class(param->m_memory_class_sizing) ||
127 init_instruments(param) ||
128 init_events_waits_history_long(
129 param->m_events_waits_history_long_sizing) ||
130 init_events_stages_history_long(
131 param->m_events_stages_history_long_sizing) ||
132 init_events_statements_history_long(
133 param->m_events_statements_history_long_sizing) ||
134 init_events_transactions_history_long(
135 param->m_events_transactions_history_long_sizing) ||
136 init_file_hash(param) ||
137 init_table_share_hash(param) ||
138 init_setup_actor(param) ||
139 init_setup_actor_hash(param) ||
140 init_setup_object(param) ||
141 init_setup_object_hash(param) ||
142 init_host(param) ||
143 init_host_hash(param) ||
144 init_user(param) ||
145 init_user_hash(param) ||
146 init_account(param) ||
147 init_account_hash(param) ||
148 init_digest(param) ||
149 init_digest_hash(param) ||
150 init_program(param) ||
151 init_program_hash(param) ||
152 init_prepared_stmt(param))
153 {
154 /*
155 The performance schema initialization failed.
156 Free the memory used, and disable the instrumentation.
157 */
158 cleanup_performance_schema();
159 return NULL;
160 }
161
162 if (param->m_enabled)
163 {
164 /** Default values for SETUP_CONSUMERS */
165 flag_events_stages_current= param->m_consumer_events_stages_current_enabled;
166 flag_events_stages_history= param->m_consumer_events_stages_history_enabled;
167 flag_events_stages_history_long= param->m_consumer_events_stages_history_long_enabled;
168 flag_events_statements_current= param->m_consumer_events_statements_current_enabled;
169 flag_events_statements_history= param->m_consumer_events_statements_history_enabled;
170 flag_events_statements_history_long= param->m_consumer_events_statements_history_long_enabled;
171 flag_events_transactions_current= param->m_consumer_events_transactions_current_enabled;
172 flag_events_transactions_history= param->m_consumer_events_transactions_history_enabled;
173 flag_events_transactions_history_long= param->m_consumer_events_transactions_history_long_enabled;
174 flag_events_waits_current= param->m_consumer_events_waits_current_enabled;
175 flag_events_waits_history= param->m_consumer_events_waits_history_enabled;
176 flag_events_waits_history_long= param->m_consumer_events_waits_history_long_enabled;
177 flag_global_instrumentation= param->m_consumer_global_instrumentation_enabled;
178 flag_thread_instrumentation= param->m_consumer_thread_instrumentation_enabled;
179 flag_statements_digest= param->m_consumer_statement_digest_enabled;
180 }
181 else
182 {
183 flag_events_stages_current= false;
184 flag_events_stages_history= false;
185 flag_events_stages_history_long= false;
186 flag_events_statements_current= false;
187 flag_events_statements_history= false;
188 flag_events_statements_history_long= false;
189 flag_events_transactions_current= false;
190 flag_events_transactions_history= false;
191 flag_events_transactions_history_long= false;
192 flag_events_waits_current= false;
193 flag_events_waits_history= false;
194 flag_events_waits_history_long= false;
195 flag_global_instrumentation= false;
196 flag_thread_instrumentation= false;
197 flag_statements_digest= false;
198 }
199
200 pfs_initialized= true;
201
202 if (param->m_enabled)
203 {
204 install_default_setup(&PFS_bootstrap);
205 return &PFS_bootstrap;
206 }
207
208 return NULL;
209 }
210
destroy_pfs_thread(void * key)211 static void destroy_pfs_thread(void *key)
212 {
213 PFS_thread* pfs= reinterpret_cast<PFS_thread*> (key);
214 assert(pfs);
215 /*
216 This automatic cleanup is a last resort and best effort to avoid leaks,
217 and may not work on windows due to the implementation of pthread_key_create().
218 Please either use:
219 - my_thread_end()
220 - or PSI_server->delete_current_thread()
221 in the instrumented code, to explicitly cleanup the instrumentation.
222
223 Avoid invalid writes when the main() thread completes after shutdown:
224 the memory pointed by pfs is already released.
225 */
226 if (pfs_initialized)
227 destroy_thread(pfs);
228 }
229
cleanup_performance_schema(void)230 static void cleanup_performance_schema(void)
231 {
232 /*
233 my.cnf options
234 */
235
236 cleanup_instrument_config();
237
238 /*
239 All the LF_HASH
240 */
241
242 cleanup_setup_actor_hash();
243 cleanup_setup_object_hash();
244 cleanup_account_hash();
245 cleanup_host_hash();
246 cleanup_user_hash();
247 cleanup_program_hash();
248 cleanup_table_share_hash();
249 cleanup_file_hash();
250 cleanup_digest_hash();
251
252 /*
253 Then the lookup tables
254 */
255
256 cleanup_setup_actor();
257 cleanup_setup_object();
258
259 /*
260 Then the history tables
261 */
262
263 cleanup_events_waits_history_long();
264 cleanup_events_stages_history_long();
265 cleanup_events_statements_history_long();
266 cleanup_events_transactions_history_long();
267
268 /*
269 Then the various aggregations
270 */
271
272 cleanup_digest();
273 cleanup_account();
274 cleanup_host();
275 cleanup_user();
276
277 /*
278 Then the instrument classes.
279 Once a class is cleaned up,
280 find_XXX_class(key)
281 will return PSI_NOT_INSTRUMENTED
282 */
283 cleanup_program();
284 cleanup_prepared_stmt();
285 cleanup_sync_class();
286 cleanup_thread_class();
287 cleanup_table_share();
288 cleanup_table_share_lock_stat();
289 cleanup_table_share_index_stat();
290 cleanup_file_class();
291 cleanup_stage_class();
292 cleanup_statement_class();
293 cleanup_socket_class();
294 cleanup_memory_class();
295
296 cleanup_instruments();
297 }
298
shutdown_performance_schema(void)299 void shutdown_performance_schema(void)
300 {
301 pfs_initialized= false;
302
303 /* disable everything, especially for this thread. */
304 flag_events_stages_current= false;
305 flag_events_stages_history= false;
306 flag_events_stages_history_long= false;
307 flag_events_statements_current= false;
308 flag_events_statements_history= false;
309 flag_events_statements_history_long= false;
310 flag_events_transactions_current= false;
311 flag_events_transactions_history= false;
312 flag_events_transactions_history_long= false;
313 flag_events_waits_current= false;
314 flag_events_waits_history= false;
315 flag_events_waits_history_long= false;
316 flag_global_instrumentation= false;
317 flag_thread_instrumentation= false;
318 flag_statements_digest= false;
319
320 global_table_io_class.m_enabled= false;
321 global_table_lock_class.m_enabled= false;
322 global_idle_class.m_enabled= false;
323 global_metadata_class.m_enabled= false;
324 global_transaction_class.m_enabled= false;
325
326 cleanup_performance_schema();
327 /*
328 Be careful to not delete un-initialized keys,
329 this would affect key 0, which is THR_KEY_mysys,
330 */
331 if (THR_PFS_initialized)
332 {
333 my_set_thread_local(THR_PFS, NULL);
334 my_set_thread_local(THR_PFS_VG, NULL); // global_variables
335 my_set_thread_local(THR_PFS_SV, NULL); // session_variables
336 my_set_thread_local(THR_PFS_VBT, NULL); // variables_by_thread
337 my_set_thread_local(THR_PFS_SG, NULL); // global_status
338 my_set_thread_local(THR_PFS_SS, NULL); // session_status
339 my_set_thread_local(THR_PFS_SBT, NULL); // status_by_thread
340 my_set_thread_local(THR_PFS_SBU, NULL); // status_by_user
341 my_set_thread_local(THR_PFS_SBH, NULL); // status_by_host
342 my_set_thread_local(THR_PFS_SBA, NULL); // status_by_account
343
344 my_delete_thread_local_key(THR_PFS);
345 my_delete_thread_local_key(THR_PFS_VG);
346 my_delete_thread_local_key(THR_PFS_SV);
347 my_delete_thread_local_key(THR_PFS_VBT);
348 my_delete_thread_local_key(THR_PFS_SG);
349 my_delete_thread_local_key(THR_PFS_SS);
350 my_delete_thread_local_key(THR_PFS_SBT);
351 my_delete_thread_local_key(THR_PFS_SBU);
352 my_delete_thread_local_key(THR_PFS_SBH);
353 my_delete_thread_local_key(THR_PFS_SBA);
354
355 THR_PFS_initialized= false;
356 }
357 }
358
359 /**
360 Initialize the dynamic array used to hold PFS_INSTRUMENT configuration
361 options.
362 */
init_pfs_instrument_array()363 void init_pfs_instrument_array()
364 {
365 pfs_instr_config_array= new Pfs_instr_config_array(PSI_NOT_INSTRUMENTED);
366 }
367
368 /**
369 Deallocate the PFS_INSTRUMENT array.
370 */
cleanup_instrument_config()371 void cleanup_instrument_config()
372 {
373 if (pfs_instr_config_array != NULL)
374 my_free_container_pointers(*pfs_instr_config_array);
375 delete pfs_instr_config_array;
376 pfs_instr_config_array= NULL;
377 }
378
379 /**
380 Process one performance_schema_instrument configuration string. Isolate the
381 instrument name, evaluate the option value, and store them in a dynamic array.
382 Return 'false' for success, 'true' for error.
383
384 @param name Instrument name
385 @param value Configuration option: 'on', 'off', etc.
386 @return 0 for success, non zero for errors
387 */
388
add_pfs_instr_to_array(const char * name,const char * value)389 int add_pfs_instr_to_array(const char* name, const char* value)
390 {
391 size_t name_length= strlen(name);
392 size_t value_length= strlen(value);
393
394 /* Allocate structure plus string buffers plus null terminators */
395 PFS_instr_config* e = (PFS_instr_config*)my_malloc(PSI_NOT_INSTRUMENTED,
396 sizeof(PFS_instr_config)
397 + name_length + 1 + value_length + 1, MYF(MY_WME));
398 if (!e) return 1;
399
400 /* Copy the instrument name */
401 e->m_name= (char*)e + sizeof(PFS_instr_config);
402 memcpy(e->m_name, name, name_length);
403 e->m_name_length= (uint)name_length;
404 e->m_name[name_length]= '\0';
405
406 /* Set flags accordingly */
407 if (!my_strcasecmp(&my_charset_latin1, value, "counted"))
408 {
409 e->m_enabled= true;
410 e->m_timed= false;
411 }
412 else
413 if (!my_strcasecmp(&my_charset_latin1, value, "true") ||
414 !my_strcasecmp(&my_charset_latin1, value, "on") ||
415 !my_strcasecmp(&my_charset_latin1, value, "1") ||
416 !my_strcasecmp(&my_charset_latin1, value, "yes"))
417 {
418 e->m_enabled= true;
419 e->m_timed= true;
420 }
421 else
422 if (!my_strcasecmp(&my_charset_latin1, value, "false") ||
423 !my_strcasecmp(&my_charset_latin1, value, "off") ||
424 !my_strcasecmp(&my_charset_latin1, value, "0") ||
425 !my_strcasecmp(&my_charset_latin1, value, "no"))
426 {
427 e->m_enabled= false;
428 e->m_timed= false;
429 }
430 else
431 {
432 my_free(e);
433 return 1;
434 }
435
436 /* Add to the array of default startup options */
437 if (pfs_instr_config_array->push_back(e))
438 {
439 my_free(e);
440 return 1;
441 }
442
443 return 0;
444 }
445