1/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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 as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software Foundation,
14 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15
16/**
17 @file storage/perfschema/pfs_server.cc
18 Private interface for the server (implementation).
19*/
20
21#include "my_global.h"
22#include "my_sys.h"
23#include "mysys_err.h"
24#include "pfs_server.h"
25#include "pfs.h"
26#include "pfs_global.h"
27#include "pfs_instr_class.h"
28#include "pfs_instr.h"
29#include "pfs_events_waits.h"
30#include "pfs_events_stages.h"
31#include "pfs_events_statements.h"
32#include "pfs_timer.h"
33#include "pfs_setup_actor.h"
34#include "pfs_setup_object.h"
35#include "pfs_host.h"
36#include "pfs_user.h"
37#include "pfs_account.h"
38#include "pfs_defaults.h"
39#include "pfs_digest.h"
40
41PFS_global_param pfs_param;
42
43PFS_table_stat PFS_table_stat::g_reset_template;
44
45C_MODE_START
46static void destroy_pfs_thread(void *key);
47C_MODE_END
48
49static void cleanup_performance_schema(void);
50void cleanup_instrument_config(void);
51
52struct PSI_bootstrap*
53initialize_performance_schema(PFS_global_param *param)
54{
55 pfs_initialized= false;
56
57 PFS_table_stat::g_reset_template.reset();
58 global_idle_stat.reset();
59 global_table_io_stat.reset();
60 global_table_lock_stat.reset();
61
62 pfs_automated_sizing(param);
63
64 if (! param->m_enabled)
65 {
66 /*
67 The performance schema is disabled in the startup command line.
68 All the instrumentation is turned off.
69 */
70 pfs_enabled= 0;
71 return NULL;
72 }
73 pfs_enabled= TRUE;
74
75 init_timers();
76
77 init_event_name_sizing(param);
78 register_global_classes();
79
80 if (pthread_key_create(&THR_PFS, destroy_pfs_thread))
81 return NULL;
82
83 THR_PFS_initialized= true;
84
85 if (init_sync_class(param->m_mutex_class_sizing,
86 param->m_rwlock_class_sizing,
87 param->m_cond_class_sizing) ||
88 init_thread_class(param->m_thread_class_sizing) ||
89 init_table_share(param->m_table_share_sizing) ||
90 init_file_class(param->m_file_class_sizing) ||
91 init_stage_class(param->m_stage_class_sizing) ||
92 init_statement_class(param->m_statement_class_sizing) ||
93 init_socket_class(param->m_socket_class_sizing) ||
94 init_instruments(param) ||
95 init_events_waits_history_long(
96 param->m_events_waits_history_long_sizing) ||
97 init_events_stages_history_long(
98 param->m_events_stages_history_long_sizing) ||
99 init_events_statements_history_long(
100 param->m_events_statements_history_long_sizing) ||
101 init_file_hash() ||
102 init_table_share_hash() ||
103 init_setup_actor(param) ||
104 init_setup_actor_hash() ||
105 init_setup_object(param) ||
106 init_setup_object_hash() ||
107 init_host(param) ||
108 init_host_hash() ||
109 init_user(param) ||
110 init_user_hash() ||
111 init_account(param) ||
112 init_account_hash() ||
113 init_digest(param) ||
114 init_digest_hash())
115 {
116 /*
117 The performance schema initialization failed.
118 Free the memory used, and disable the instrumentation.
119 */
120 cleanup_performance_schema();
121 return NULL;
122 }
123
124 pfs_initialized= true;
125
126 /** Default values for SETUP_CONSUMERS */
127 flag_events_stages_current= param->m_consumer_events_stages_current_enabled;
128 flag_events_stages_history= param->m_consumer_events_stages_history_enabled;
129 flag_events_stages_history_long= param->m_consumer_events_stages_history_long_enabled;
130 flag_events_statements_current= param->m_consumer_events_statements_current_enabled;
131 flag_events_statements_history= param->m_consumer_events_statements_history_enabled;
132 flag_events_statements_history_long= param->m_consumer_events_statements_history_long_enabled;
133 flag_events_waits_current= param->m_consumer_events_waits_current_enabled;
134 flag_events_waits_history= param->m_consumer_events_waits_history_enabled;
135 flag_events_waits_history_long= param->m_consumer_events_waits_history_long_enabled;
136 flag_global_instrumentation= param->m_consumer_global_instrumentation_enabled;
137 flag_thread_instrumentation= param->m_consumer_thread_instrumentation_enabled;
138 flag_statements_digest= param->m_consumer_statement_digest_enabled;
139
140 install_default_setup(&PFS_bootstrap);
141 return &PFS_bootstrap;
142}
143
144static void destroy_pfs_thread(void *key)
145{
146 PFS_thread* pfs= reinterpret_cast<PFS_thread*> (key);
147 DBUG_ASSERT(pfs);
148 /*
149 This automatic cleanup is a last resort and best effort to avoid leaks,
150 and may not work on windows due to the implementation of pthread_key_create().
151 Please either use:
152 - my_thread_end()
153 - or PSI_server->delete_current_thread()
154 in the instrumented code, to explicitly cleanup the instrumentation.
155
156 Avoid invalid writes when the main() thread completes after shutdown:
157 the memory pointed by pfs is already released.
158 */
159 if (pfs_initialized)
160 destroy_thread(pfs);
161}
162
163static void cleanup_performance_schema(void)
164{
165 cleanup_instrument_config();
166 cleanup_instruments();
167 cleanup_sync_class();
168 cleanup_thread_class();
169 cleanup_table_share();
170 cleanup_file_class();
171 cleanup_stage_class();
172 cleanup_statement_class();
173 cleanup_socket_class();
174 cleanup_events_waits_history_long();
175 cleanup_events_stages_history_long();
176 cleanup_events_statements_history_long();
177 cleanup_table_share_hash();
178 cleanup_file_hash();
179 cleanup_setup_actor();
180 cleanup_setup_actor_hash();
181 cleanup_setup_object();
182 cleanup_setup_object_hash();
183 cleanup_host();
184 cleanup_host_hash();
185 cleanup_user();
186 cleanup_user_hash();
187 cleanup_account();
188 cleanup_account_hash();
189 cleanup_digest();
190 cleanup_digest_hash();
191}
192
193void shutdown_performance_schema(void)
194{
195 pfs_initialized= false;
196 cleanup_performance_schema();
197#if 0
198 /*
199 Be careful to not delete un-initialized keys,
200 this would affect key 0, which is THR_KEY_mysys,
201 */
202 if (THR_PFS_initialized)
203 {
204 my_pthread_setspecific_ptr(THR_PFS, NULL);
205 pthread_key_delete(THR_PFS);
206 THR_PFS_initialized= false;
207 }
208#endif
209}
210
211/**
212 Initialize the dynamic array used to hold PFS_INSTRUMENT configuration
213 options.
214*/
215void init_pfs_instrument_array()
216{
217 my_init_dynamic_array(&pfs_instr_config_array, sizeof(PFS_instr_config*),
218 10, 10, MYF(0));
219 pfs_instr_config_state= PFS_INSTR_CONFIG_ALLOCATED;
220}
221
222/**
223 Deallocate the PFS_INSTRUMENT array. Use an atomic compare-and-swap to ensure
224 that it is deallocated only once in the chaotic environment of server shutdown.
225*/
226void cleanup_instrument_config()
227{
228 int desired_state= PFS_INSTR_CONFIG_ALLOCATED;
229
230 /* Ignore if another thread has already deallocated the array */
231 if (my_atomic_cas32(&pfs_instr_config_state, &desired_state, PFS_INSTR_CONFIG_DEALLOCATED))
232 {
233 PFS_instr_config **array=dynamic_element(&pfs_instr_config_array, 0, PFS_instr_config**);
234 for (uint i=0; i < pfs_instr_config_array.elements; i++)
235 my_free(array[i]);
236 delete_dynamic(&pfs_instr_config_array);
237 }
238}
239
240/**
241 Process one performance_schema_instrument configuration string. Isolate the
242 instrument name, evaluate the option value, and store them in a dynamic array.
243 Return 'false' for success, 'true' for error.
244
245 @param name Instrument name
246 @param value Configuration option: 'on', 'off', etc.
247 @return 0 for success, non zero for errors
248*/
249
250int add_pfs_instr_to_array(const char* name, const char* value)
251{
252 size_t name_length= strlen(name);
253 size_t value_length= strlen(value);
254
255 /* Allocate structure plus string buffers plus null terminators */
256 PFS_instr_config* e = (PFS_instr_config*)my_malloc(sizeof(PFS_instr_config)
257 + name_length + 1 + value_length + 1, MYF(MY_WME));
258 if (!e) return 1;
259
260 /* Copy the instrument name */
261 e->m_name= (char*)e + sizeof(PFS_instr_config);
262 memcpy(e->m_name, name, name_length);
263 e->m_name_length= (uint)name_length;
264 e->m_name[name_length]= '\0';
265
266 /* Set flags accordingly */
267 if (!my_strcasecmp(&my_charset_latin1, value, "counted"))
268 {
269 e->m_enabled= true;
270 e->m_timed= false;
271 }
272 else
273 if (!my_strcasecmp(&my_charset_latin1, value, "true") ||
274 !my_strcasecmp(&my_charset_latin1, value, "on") ||
275 !my_strcasecmp(&my_charset_latin1, value, "1") ||
276 !my_strcasecmp(&my_charset_latin1, value, "yes"))
277 {
278 e->m_enabled= true;
279 e->m_timed= true;
280 }
281 else
282 if (!my_strcasecmp(&my_charset_latin1, value, "false") ||
283 !my_strcasecmp(&my_charset_latin1, value, "off") ||
284 !my_strcasecmp(&my_charset_latin1, value, "0") ||
285 !my_strcasecmp(&my_charset_latin1, value, "no"))
286 {
287 e->m_enabled= false;
288 e->m_timed= false;
289 }
290 else
291 {
292 my_free(e);
293 return 1;
294 }
295
296 /* Add to the array of default startup options */
297 if (insert_dynamic(&pfs_instr_config_array, &e))
298 {
299 my_free(e);
300 return 1;
301 }
302
303 return 0;
304}
305