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