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 | |
41 | PFS_global_param pfs_param; |
42 | |
43 | PFS_table_stat PFS_table_stat::g_reset_template; |
44 | |
45 | C_MODE_START |
46 | static void destroy_pfs_thread(void *key); |
47 | C_MODE_END |
48 | |
49 | static void cleanup_performance_schema(void); |
50 | void cleanup_instrument_config(void); |
51 | |
52 | struct PSI_bootstrap* |
53 | initialize_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 | |
144 | static 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 | |
163 | static 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 | |
193 | void 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 | */ |
215 | void 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 | */ |
226 | void 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 | |
250 | int 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 | |