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_instr_class.cc |
18 | Performance schema instruments meta data (implementation). |
19 | */ |
20 | |
21 | #include "my_global.h" |
22 | #include "my_sys.h" |
23 | #include "structs.h" |
24 | #include "table.h" |
25 | #include "pfs_instr_class.h" |
26 | #include "pfs_instr.h" |
27 | #include "pfs_global.h" |
28 | #include "pfs_timer.h" |
29 | #include "pfs_events_waits.h" |
30 | #include "pfs_setup_object.h" |
31 | #include "pfs_atomic.h" |
32 | #include "mysql/psi/mysql_thread.h" |
33 | #include "lf.h" |
34 | |
35 | #include <string.h> |
36 | |
37 | /** |
38 | @defgroup Performance_schema_buffers Performance Schema Buffers |
39 | @ingroup Performance_schema_implementation |
40 | @{ |
41 | */ |
42 | |
43 | /** |
44 | PFS_INSTRUMENT option settings array and associated state variable to |
45 | serialize access during shutdown. |
46 | */ |
47 | DYNAMIC_ARRAY pfs_instr_config_array; |
48 | int pfs_instr_config_state= PFS_INSTR_CONFIG_NOT_INITIALIZED; |
49 | |
50 | static void configure_instr_class(PFS_instr_class *entry); |
51 | |
52 | static void init_instr_class(PFS_instr_class *klass, |
53 | const char *name, |
54 | uint name_length, |
55 | int flags, |
56 | PFS_class_type class_type); |
57 | |
58 | /** |
59 | Current number of elements in mutex_class_array. |
60 | This global variable is written to during: |
61 | - the performance schema initialization |
62 | - a plugin initialization |
63 | */ |
64 | static volatile uint32 mutex_class_dirty_count= 0; |
65 | static volatile uint32 mutex_class_allocated_count= 0; |
66 | static volatile uint32 rwlock_class_dirty_count= 0; |
67 | static volatile uint32 rwlock_class_allocated_count= 0; |
68 | static volatile uint32 cond_class_dirty_count= 0; |
69 | static volatile uint32 cond_class_allocated_count= 0; |
70 | |
71 | /** Size of the mutex class array. @sa mutex_class_array */ |
72 | ulong mutex_class_max= 0; |
73 | /** Number of mutex class lost. @sa mutex_class_array */ |
74 | ulong mutex_class_lost= 0; |
75 | /** Size of the rwlock class array. @sa rwlock_class_array */ |
76 | ulong rwlock_class_max= 0; |
77 | /** Number of rwlock class lost. @sa rwlock_class_array */ |
78 | ulong rwlock_class_lost= 0; |
79 | /** Size of the condition class array. @sa cond_class_array */ |
80 | ulong cond_class_max= 0; |
81 | /** Number of condition class lost. @sa cond_class_array */ |
82 | ulong cond_class_lost= 0; |
83 | /** Size of the thread class array. @sa thread_class_array */ |
84 | ulong thread_class_max= 0; |
85 | /** Number of thread class lost. @sa thread_class_array */ |
86 | ulong thread_class_lost= 0; |
87 | /** Size of the file class array. @sa file_class_array */ |
88 | ulong file_class_max= 0; |
89 | /** Number of file class lost. @sa file_class_array */ |
90 | ulong file_class_lost= 0; |
91 | /** Size of the stage class array. @sa stage_class_array */ |
92 | ulong stage_class_max= 0; |
93 | /** Number of stage class lost. @sa stage_class_array */ |
94 | ulong stage_class_lost= 0; |
95 | /** Size of the statement class array. @sa statement_class_array */ |
96 | ulong statement_class_max= 0; |
97 | /** Number of statement class lost. @sa statement_class_array */ |
98 | ulong statement_class_lost= 0; |
99 | /** Size of the table share array. @sa table_share_array */ |
100 | ulong table_share_max= 0; |
101 | /** Number of table share lost. @sa table_share_array */ |
102 | ulong table_share_lost= 0; |
103 | /** Size of the socket class array. @sa socket_class_array */ |
104 | ulong socket_class_max= 0; |
105 | /** Number of socket class lost. @sa socket_class_array */ |
106 | ulong socket_class_lost= 0; |
107 | |
108 | PFS_mutex_class *mutex_class_array= NULL; |
109 | PFS_rwlock_class *rwlock_class_array= NULL; |
110 | PFS_cond_class *cond_class_array= NULL; |
111 | |
112 | /** |
113 | Current number or elements in thread_class_array. |
114 | This global variable is written to during: |
115 | - the performance schema initialization |
116 | - a plugin initialization |
117 | */ |
118 | static volatile uint32 thread_class_dirty_count= 0; |
119 | static volatile uint32 thread_class_allocated_count= 0; |
120 | |
121 | static PFS_thread_class *thread_class_array= NULL; |
122 | |
123 | /** |
124 | Table instance array. |
125 | @sa table_share_max |
126 | @sa table_share_lost |
127 | @sa table_share_hash |
128 | */ |
129 | PFS_table_share *table_share_array= NULL; |
130 | |
131 | PFS_ALIGNED PFS_single_stat global_idle_stat; |
132 | PFS_ALIGNED PFS_table_io_stat global_table_io_stat; |
133 | PFS_ALIGNED PFS_table_lock_stat global_table_lock_stat; |
134 | PFS_ALIGNED PFS_instr_class global_table_io_class; |
135 | PFS_ALIGNED PFS_instr_class global_table_lock_class; |
136 | PFS_ALIGNED PFS_instr_class global_idle_class; |
137 | |
138 | /** Class-timer map */ |
139 | enum_timer_name *class_timers[] = |
140 | {&wait_timer, /* PFS_CLASS_NONE */ |
141 | &wait_timer, /* PFS_CLASS_MUTEX */ |
142 | &wait_timer, /* PFS_CLASS_RWLOCK */ |
143 | &wait_timer, /* PFS_CLASS_COND */ |
144 | &wait_timer, /* PFS_CLASS_FILE */ |
145 | &wait_timer, /* PFS_CLASS_TABLE */ |
146 | &stage_timer, /* PFS_CLASS_STAGE */ |
147 | &statement_timer, /* PFS_CLASS_STATEMENT */ |
148 | &wait_timer, /* PFS_CLASS_SOCKET */ |
149 | &wait_timer, /* PFS_CLASS_TABLE_IO */ |
150 | &wait_timer, /* PFS_CLASS_TABLE_LOCK */ |
151 | &idle_timer /* PFS_CLASS_IDLE */ |
152 | }; |
153 | |
154 | /** |
155 | Hash index for instrumented table shares. |
156 | This index is searched by table fully qualified name (@c PFS_table_share_key), |
157 | and points to instrumented table shares (@c PFS_table_share). |
158 | @sa table_share_array |
159 | @sa PFS_table_share_key |
160 | @sa PFS_table_share |
161 | @sa table_share_hash_get_key |
162 | @sa get_table_share_hash_pins |
163 | */ |
164 | LF_HASH table_share_hash; |
165 | /** True if table_share_hash is initialized. */ |
166 | static bool table_share_hash_inited= false; |
167 | |
168 | static volatile uint32 file_class_dirty_count= 0; |
169 | static volatile uint32 file_class_allocated_count= 0; |
170 | |
171 | PFS_file_class *file_class_array= NULL; |
172 | |
173 | static volatile uint32 stage_class_dirty_count= 0; |
174 | static volatile uint32 stage_class_allocated_count= 0; |
175 | |
176 | static PFS_stage_class *stage_class_array= NULL; |
177 | |
178 | static volatile uint32 statement_class_dirty_count= 0; |
179 | static volatile uint32 statement_class_allocated_count= 0; |
180 | |
181 | static PFS_statement_class *statement_class_array= NULL; |
182 | |
183 | static volatile uint32 socket_class_dirty_count= 0; |
184 | static volatile uint32 socket_class_allocated_count= 0; |
185 | |
186 | static PFS_socket_class *socket_class_array= NULL; |
187 | |
188 | uint mutex_class_start= 0; |
189 | uint rwlock_class_start= 0; |
190 | uint cond_class_start= 0; |
191 | uint file_class_start= 0; |
192 | uint wait_class_max= 0; |
193 | uint socket_class_start= 0; |
194 | |
195 | void init_event_name_sizing(const PFS_global_param *param) |
196 | { |
197 | mutex_class_start= 3; /* global table io, table lock, idle */ |
198 | rwlock_class_start= mutex_class_start + param->m_mutex_class_sizing; |
199 | cond_class_start= rwlock_class_start + param->m_rwlock_class_sizing; |
200 | file_class_start= cond_class_start + param->m_cond_class_sizing; |
201 | socket_class_start= file_class_start + param->m_file_class_sizing; |
202 | wait_class_max= socket_class_start + param->m_socket_class_sizing; |
203 | } |
204 | |
205 | void register_global_classes() |
206 | { |
207 | /* Table IO class */ |
208 | init_instr_class(&global_table_io_class, "wait/io/table/sql/handler" , 25, |
209 | 0, PFS_CLASS_TABLE_IO); |
210 | global_table_io_class.m_event_name_index= GLOBAL_TABLE_IO_EVENT_INDEX; |
211 | configure_instr_class(&global_table_io_class); |
212 | |
213 | /* Table lock class */ |
214 | init_instr_class(&global_table_lock_class, "wait/lock/table/sql/handler" , 27, |
215 | 0, PFS_CLASS_TABLE_LOCK); |
216 | global_table_lock_class.m_event_name_index= GLOBAL_TABLE_LOCK_EVENT_INDEX; |
217 | configure_instr_class(&global_table_lock_class); |
218 | |
219 | /* Idle class */ |
220 | init_instr_class(&global_idle_class, "idle" , 4, |
221 | 0, PFS_CLASS_IDLE); |
222 | global_idle_class.m_event_name_index= GLOBAL_IDLE_EVENT_INDEX; |
223 | configure_instr_class(&global_idle_class); |
224 | } |
225 | |
226 | /** |
227 | Initialize the instrument synch class buffers. |
228 | @param mutex_class_sizing max number of mutex class |
229 | @param rwlock_class_sizing max number of rwlock class |
230 | @param cond_class_sizing max number of condition class |
231 | @return 0 on success |
232 | */ |
233 | int init_sync_class(uint mutex_class_sizing, |
234 | uint rwlock_class_sizing, |
235 | uint cond_class_sizing) |
236 | { |
237 | mutex_class_dirty_count= mutex_class_allocated_count= 0; |
238 | rwlock_class_dirty_count= rwlock_class_allocated_count= 0; |
239 | cond_class_dirty_count= cond_class_allocated_count= 0; |
240 | mutex_class_max= mutex_class_sizing; |
241 | rwlock_class_max= rwlock_class_sizing; |
242 | cond_class_max= cond_class_sizing; |
243 | mutex_class_lost= rwlock_class_lost= cond_class_lost= 0; |
244 | |
245 | mutex_class_array= NULL; |
246 | rwlock_class_array= NULL; |
247 | cond_class_array= NULL; |
248 | |
249 | if (mutex_class_max > 0) |
250 | { |
251 | mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, sizeof(PFS_mutex_class), |
252 | PFS_mutex_class, MYF(MY_ZEROFILL)); |
253 | if (unlikely(mutex_class_array == NULL)) |
254 | return 1; |
255 | } |
256 | |
257 | if (rwlock_class_max > 0) |
258 | { |
259 | rwlock_class_array= PFS_MALLOC_ARRAY(rwlock_class_max, sizeof(PFS_rwlock_class), |
260 | PFS_rwlock_class, MYF(MY_ZEROFILL)); |
261 | if (unlikely(rwlock_class_array == NULL)) |
262 | return 1; |
263 | } |
264 | |
265 | if (cond_class_max > 0) |
266 | { |
267 | cond_class_array= PFS_MALLOC_ARRAY(cond_class_max, sizeof(PFS_cond_class), |
268 | PFS_cond_class, MYF(MY_ZEROFILL)); |
269 | if (unlikely(cond_class_array == NULL)) |
270 | return 1; |
271 | } |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | /** Cleanup the instrument synch class buffers. */ |
277 | void cleanup_sync_class(void) |
278 | { |
279 | pfs_free(mutex_class_array); |
280 | mutex_class_array= NULL; |
281 | mutex_class_dirty_count= mutex_class_allocated_count= mutex_class_max= 0; |
282 | pfs_free(rwlock_class_array); |
283 | rwlock_class_array= NULL; |
284 | rwlock_class_dirty_count= rwlock_class_allocated_count= rwlock_class_max= 0; |
285 | pfs_free(cond_class_array); |
286 | cond_class_array= NULL; |
287 | cond_class_dirty_count= cond_class_allocated_count= cond_class_max= 0; |
288 | } |
289 | |
290 | /** |
291 | Initialize the thread class buffer. |
292 | @param thread_class_sizing max number of thread class |
293 | @return 0 on success |
294 | */ |
295 | int init_thread_class(uint thread_class_sizing) |
296 | { |
297 | int result= 0; |
298 | thread_class_dirty_count= thread_class_allocated_count= 0; |
299 | thread_class_max= thread_class_sizing; |
300 | thread_class_lost= 0; |
301 | |
302 | if (thread_class_max > 0) |
303 | { |
304 | thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, sizeof(PFS_thread_class), |
305 | PFS_thread_class, MYF(MY_ZEROFILL)); |
306 | if (unlikely(thread_class_array == NULL)) |
307 | result= 1; |
308 | } |
309 | else |
310 | thread_class_array= NULL; |
311 | |
312 | return result; |
313 | } |
314 | |
315 | /** Cleanup the thread class buffers. */ |
316 | void cleanup_thread_class(void) |
317 | { |
318 | pfs_free(thread_class_array); |
319 | thread_class_array= NULL; |
320 | thread_class_dirty_count= thread_class_allocated_count= 0; |
321 | thread_class_max= 0; |
322 | } |
323 | |
324 | /** |
325 | Initialize the table share buffer. |
326 | @param table_share_sizing max number of table share |
327 | @return 0 on success |
328 | */ |
329 | int init_table_share(uint table_share_sizing) |
330 | { |
331 | int result= 0; |
332 | table_share_max= table_share_sizing; |
333 | table_share_lost= 0; |
334 | |
335 | if (table_share_max > 0) |
336 | { |
337 | table_share_array= PFS_MALLOC_ARRAY(table_share_max, sizeof(PFS_table_share), |
338 | PFS_table_share, MYF(MY_ZEROFILL)); |
339 | if (unlikely(table_share_array == NULL)) |
340 | result= 1; |
341 | } |
342 | else |
343 | table_share_array= NULL; |
344 | |
345 | return result; |
346 | } |
347 | |
348 | /** Cleanup the table share buffers. */ |
349 | void cleanup_table_share(void) |
350 | { |
351 | pfs_free(table_share_array); |
352 | table_share_array= NULL; |
353 | table_share_max= 0; |
354 | } |
355 | |
356 | C_MODE_START |
357 | /** get_key function for @c table_share_hash. */ |
358 | static uchar *table_share_hash_get_key(const uchar *entry, size_t *length, |
359 | my_bool) |
360 | { |
361 | const PFS_table_share * const *typed_entry; |
362 | const PFS_table_share *share; |
363 | const void *result; |
364 | typed_entry= reinterpret_cast<const PFS_table_share* const *> (entry); |
365 | DBUG_ASSERT(typed_entry != NULL); |
366 | share= *typed_entry; |
367 | DBUG_ASSERT(share != NULL); |
368 | *length= share->m_key.m_key_length; |
369 | result= &share->m_key.m_hash_key[0]; |
370 | return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); |
371 | } |
372 | C_MODE_END |
373 | |
374 | /** Initialize the table share hash table. */ |
375 | int init_table_share_hash(void) |
376 | { |
377 | if ((! table_share_hash_inited) && (table_share_max > 0)) |
378 | { |
379 | lf_hash_init(&table_share_hash, sizeof(PFS_table_share*), LF_HASH_UNIQUE, |
380 | 0, 0, table_share_hash_get_key, &my_charset_bin); |
381 | /* table_share_hash.size= table_share_max; */ |
382 | table_share_hash_inited= true; |
383 | } |
384 | return 0; |
385 | } |
386 | |
387 | /** Cleanup the table share hash table. */ |
388 | void cleanup_table_share_hash(void) |
389 | { |
390 | if (table_share_hash_inited) |
391 | { |
392 | lf_hash_destroy(&table_share_hash); |
393 | table_share_hash_inited= false; |
394 | } |
395 | } |
396 | |
397 | /** |
398 | Get the hash pins for @sa table_share_hash. |
399 | @param thread The running thread. |
400 | @returns The LF_HASH pins for the thread. |
401 | */ |
402 | LF_PINS* get_table_share_hash_pins(PFS_thread *thread) |
403 | { |
404 | if (unlikely(thread->m_table_share_hash_pins == NULL)) |
405 | { |
406 | if (! table_share_hash_inited) |
407 | return NULL; |
408 | thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash); |
409 | } |
410 | return thread->m_table_share_hash_pins; |
411 | } |
412 | |
413 | /** |
414 | Set a table share hash key. |
415 | @param [out] key The key to populate. |
416 | @param temporary True for TEMPORARY TABLE. |
417 | @param schema_name The table schema name. |
418 | @param schema_name_length The table schema name length. |
419 | @param table_name The table name. |
420 | @param table_name_length The table name length. |
421 | */ |
422 | static void set_table_share_key(PFS_table_share_key *key, |
423 | bool temporary, |
424 | const char *schema_name, uint schema_name_length, |
425 | const char *table_name, uint table_name_length) |
426 | { |
427 | DBUG_ASSERT(schema_name_length <= NAME_LEN); |
428 | DBUG_ASSERT(table_name_length <= NAME_LEN); |
429 | char *saved_schema_name; |
430 | char *saved_table_name; |
431 | |
432 | char *ptr= &key->m_hash_key[0]; |
433 | ptr[0]= (temporary ? OBJECT_TYPE_TEMPORARY_TABLE : OBJECT_TYPE_TABLE); |
434 | ptr++; |
435 | saved_schema_name= ptr; |
436 | memcpy(ptr, schema_name, schema_name_length); |
437 | ptr+= schema_name_length; |
438 | ptr[0]= 0; |
439 | ptr++; |
440 | saved_table_name= ptr; |
441 | memcpy(ptr, table_name, table_name_length); |
442 | ptr+= table_name_length; |
443 | ptr[0]= 0; |
444 | ptr++; |
445 | key->m_key_length= (uint)(ptr - &key->m_hash_key[0]); |
446 | |
447 | if (lower_case_table_names) |
448 | { |
449 | my_casedn_str(files_charset_info, saved_schema_name); |
450 | my_casedn_str(files_charset_info, saved_table_name); |
451 | } |
452 | } |
453 | |
454 | void PFS_table_share::refresh_setup_object_flags(PFS_thread *thread) |
455 | { |
456 | lookup_setup_object(thread, |
457 | OBJECT_TYPE_TABLE, |
458 | m_schema_name, m_schema_name_length, |
459 | m_table_name, m_table_name_length, |
460 | &m_enabled, &m_timed); |
461 | } |
462 | |
463 | /** |
464 | Initialize the file class buffer. |
465 | @param file_class_sizing max number of file class |
466 | @return 0 on success |
467 | */ |
468 | int init_file_class(uint file_class_sizing) |
469 | { |
470 | int result= 0; |
471 | file_class_dirty_count= file_class_allocated_count= 0; |
472 | file_class_max= file_class_sizing; |
473 | file_class_lost= 0; |
474 | |
475 | if (file_class_max > 0) |
476 | { |
477 | file_class_array= PFS_MALLOC_ARRAY(file_class_max, sizeof(PFS_file_class), |
478 | PFS_file_class, MYF(MY_ZEROFILL)); |
479 | if (unlikely(file_class_array == NULL)) |
480 | return 1; |
481 | } |
482 | else |
483 | file_class_array= NULL; |
484 | |
485 | return result; |
486 | } |
487 | |
488 | /** Cleanup the file class buffers. */ |
489 | void cleanup_file_class(void) |
490 | { |
491 | pfs_free(file_class_array); |
492 | file_class_array= NULL; |
493 | file_class_dirty_count= file_class_allocated_count= 0; |
494 | file_class_max= 0; |
495 | } |
496 | |
497 | /** |
498 | Initialize the stage class buffer. |
499 | @param stage_class_sizing max number of stage class |
500 | @return 0 on success |
501 | */ |
502 | int init_stage_class(uint stage_class_sizing) |
503 | { |
504 | int result= 0; |
505 | stage_class_dirty_count= stage_class_allocated_count= 0; |
506 | stage_class_max= stage_class_sizing; |
507 | stage_class_lost= 0; |
508 | |
509 | if (stage_class_max > 0) |
510 | { |
511 | stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, sizeof(PFS_stage_class), |
512 | PFS_stage_class, MYF(MY_ZEROFILL)); |
513 | if (unlikely(stage_class_array == NULL)) |
514 | return 1; |
515 | } |
516 | else |
517 | stage_class_array= NULL; |
518 | |
519 | return result; |
520 | } |
521 | |
522 | /** Cleanup the stage class buffers. */ |
523 | void cleanup_stage_class(void) |
524 | { |
525 | pfs_free(stage_class_array); |
526 | stage_class_array= NULL; |
527 | stage_class_dirty_count= stage_class_allocated_count= 0; |
528 | stage_class_max= 0; |
529 | } |
530 | |
531 | /** |
532 | Initialize the statement class buffer. |
533 | @param statement_class_sizing max number of statement class |
534 | @return 0 on success |
535 | */ |
536 | int init_statement_class(uint statement_class_sizing) |
537 | { |
538 | int result= 0; |
539 | statement_class_dirty_count= statement_class_allocated_count= 0; |
540 | statement_class_max= statement_class_sizing; |
541 | statement_class_lost= 0; |
542 | |
543 | if (statement_class_max > 0) |
544 | { |
545 | statement_class_array= PFS_MALLOC_ARRAY(statement_class_max, sizeof(PFS_statement_class), |
546 | PFS_statement_class, MYF(MY_ZEROFILL)); |
547 | if (unlikely(statement_class_array == NULL)) |
548 | return 1; |
549 | } |
550 | else |
551 | statement_class_array= NULL; |
552 | |
553 | return result; |
554 | } |
555 | |
556 | /** Cleanup the statement class buffers. */ |
557 | void cleanup_statement_class(void) |
558 | { |
559 | pfs_free(statement_class_array); |
560 | statement_class_array= NULL; |
561 | statement_class_dirty_count= statement_class_allocated_count= 0; |
562 | statement_class_max= 0; |
563 | } |
564 | |
565 | /** |
566 | Initialize the socket class buffer. |
567 | @param socket_class_sizing max number of socket class |
568 | @return 0 on success |
569 | */ |
570 | int init_socket_class(uint socket_class_sizing) |
571 | { |
572 | int result= 0; |
573 | socket_class_dirty_count= socket_class_allocated_count= 0; |
574 | socket_class_max= socket_class_sizing; |
575 | socket_class_lost= 0; |
576 | |
577 | if (socket_class_max > 0) |
578 | { |
579 | socket_class_array= PFS_MALLOC_ARRAY(socket_class_max, sizeof(PFS_socket_class), |
580 | PFS_socket_class, MYF(MY_ZEROFILL)); |
581 | if (unlikely(socket_class_array == NULL)) |
582 | return 1; |
583 | } |
584 | else |
585 | socket_class_array= NULL; |
586 | |
587 | return result; |
588 | } |
589 | |
590 | /** Cleanup the socket class buffers. */ |
591 | void cleanup_socket_class(void) |
592 | { |
593 | pfs_free(socket_class_array); |
594 | socket_class_array= NULL; |
595 | socket_class_dirty_count= socket_class_allocated_count= 0; |
596 | socket_class_max= 0; |
597 | } |
598 | |
599 | static void init_instr_class(PFS_instr_class *klass, |
600 | const char *name, |
601 | uint name_length, |
602 | int flags, |
603 | PFS_class_type class_type) |
604 | { |
605 | DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH); |
606 | memset(klass, 0, sizeof(PFS_instr_class)); |
607 | strncpy(klass->m_name, name, name_length); |
608 | klass->m_name_length= name_length; |
609 | klass->m_flags= flags; |
610 | klass->m_enabled= true; |
611 | klass->m_timed= true; |
612 | klass->m_type= class_type; |
613 | klass->m_timer= class_timers[class_type]; |
614 | } |
615 | |
616 | /** |
617 | Set user-defined configuration values for an instrument. |
618 | */ |
619 | static void configure_instr_class(PFS_instr_class *entry) |
620 | { |
621 | uint match_length= 0; /* length of matching pattern */ |
622 | |
623 | for (uint i= 0; i < pfs_instr_config_array.elements; i++) |
624 | { |
625 | PFS_instr_config* e; |
626 | get_dynamic(&pfs_instr_config_array, (uchar*)&e, i); |
627 | |
628 | /** |
629 | Compare class name to all configuration entries. In case of multiple |
630 | matches, the longer specification wins. For example, the pattern |
631 | 'ABC/DEF/GHI=ON' has precedence over 'ABC/DEF/%=OFF' regardless of |
632 | position within the configuration file or command line. |
633 | |
634 | Consecutive wildcards affect the count. |
635 | */ |
636 | if (!my_wildcmp(&my_charset_latin1, |
637 | entry->m_name, entry->m_name+entry->m_name_length, |
638 | e->m_name, e->m_name+e->m_name_length, |
639 | '\\', '?','%')) |
640 | { |
641 | if (e->m_name_length >= match_length) |
642 | { |
643 | entry->m_enabled= e->m_enabled; |
644 | entry->m_timed= e->m_timed; |
645 | match_length= MY_MAX(e->m_name_length, match_length); |
646 | } |
647 | } |
648 | } |
649 | } |
650 | |
651 | #define REGISTER_CLASS_BODY_PART(INDEX, ARRAY, MAX, NAME, NAME_LENGTH) \ |
652 | for (INDEX= 0; INDEX < MAX; INDEX++) \ |
653 | { \ |
654 | entry= &ARRAY[INDEX]; \ |
655 | if ((entry->m_name_length == NAME_LENGTH) && \ |
656 | (strncmp(entry->m_name, NAME, NAME_LENGTH) == 0)) \ |
657 | { \ |
658 | DBUG_ASSERT(entry->m_flags == flags); \ |
659 | return (INDEX + 1); \ |
660 | } \ |
661 | } |
662 | |
663 | /** |
664 | Register a mutex instrumentation metadata. |
665 | @param name the instrumented name |
666 | @param name_length length in bytes of name |
667 | @param flags the instrumentation flags |
668 | @return a mutex instrumentation key |
669 | */ |
670 | PFS_sync_key register_mutex_class(const char *name, uint name_length, |
671 | int flags) |
672 | { |
673 | uint32 index; |
674 | PFS_mutex_class *entry; |
675 | |
676 | /* |
677 | This is a full array scan, which is not optimal. |
678 | This is acceptable since this code is only used at startup, |
679 | or when a plugin is loaded. |
680 | */ |
681 | REGISTER_CLASS_BODY_PART(index, mutex_class_array, mutex_class_max, |
682 | name, name_length) |
683 | /* |
684 | Note that: |
685 | mutex_class_dirty_count is incremented *before* an entry is added |
686 | mutex_class_allocated_count is incremented *after* an entry is added |
687 | */ |
688 | index= PFS_atomic::add_u32(&mutex_class_dirty_count, 1); |
689 | |
690 | if (index < mutex_class_max) |
691 | { |
692 | /* |
693 | The instrument was not found (from a possible previous |
694 | load / unload of a plugin), allocate it. |
695 | This code is safe when 2 threads execute in parallel |
696 | for different mutex classes: |
697 | - thread 1 registering class A |
698 | - thread 2 registering class B |
699 | will not collide in the same mutex_class_array[index] entry. |
700 | This code does not protect against 2 threads registering |
701 | in parallel the same class: |
702 | - thread 1 registering class A |
703 | - thread 2 registering class A |
704 | could lead to a duplicate class A entry. |
705 | This is ok, since this case can not happen in the caller: |
706 | - classes names are derived from a plugin name |
707 | ('wait/synch/mutex/<plugin>/xxx') |
708 | - 2 threads can not register concurrently the same plugin |
709 | in INSTALL PLUGIN. |
710 | */ |
711 | entry= &mutex_class_array[index]; |
712 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_MUTEX); |
713 | entry->m_mutex_stat.reset(); |
714 | entry->m_event_name_index= mutex_class_start + index; |
715 | entry->m_singleton= NULL; |
716 | entry->m_enabled= false; /* disabled by default */ |
717 | entry->m_timed= false; |
718 | |
719 | /* Set user-defined configuration options for this instrument */ |
720 | configure_instr_class(entry); |
721 | |
722 | /* |
723 | Now that this entry is populated, advertise it |
724 | |
725 | Technically, there is a small race condition here: |
726 | T0: |
727 | mutex_class_dirty_count= 10 |
728 | mutex_class_allocated_count= 10 |
729 | T1: Thread A increment mutex_class_dirty_count to 11 |
730 | T2: Thread B increment mutex_class_dirty_count to 12 |
731 | T3: Thread A populate entry 11 |
732 | T4: Thread B populate entry 12 |
733 | T5: Thread B increment mutex_class_allocated_count to 11, |
734 | advertise thread A incomplete record 11, |
735 | but does not advertise thread B complete record 12 |
736 | T6: Thread A increment mutex_class_allocated_count to 12 |
737 | This has no impact, and is acceptable. |
738 | A reader will not see record 12 for a short time. |
739 | A reader will see an incomplete record 11 for a short time, |
740 | which is ok: the mutex name / statistics will be temporarily |
741 | empty/NULL/zero, but this won't cause a crash |
742 | (mutex_class_array is initialized with MY_ZEROFILL). |
743 | */ |
744 | PFS_atomic::add_u32(&mutex_class_allocated_count, 1); |
745 | return (index + 1); |
746 | } |
747 | |
748 | /* |
749 | Out of space, report to SHOW STATUS that |
750 | the allocated memory was too small. |
751 | */ |
752 | mutex_class_lost++; |
753 | return 0; |
754 | } |
755 | |
756 | /** |
757 | Register a rwlock instrumentation metadata. |
758 | @param name the instrumented name |
759 | @param name_length length in bytes of name |
760 | @param flags the instrumentation flags |
761 | @return a rwlock instrumentation key |
762 | */ |
763 | PFS_sync_key register_rwlock_class(const char *name, uint name_length, |
764 | int flags) |
765 | { |
766 | /* See comments in register_mutex_class */ |
767 | uint32 index; |
768 | PFS_rwlock_class *entry; |
769 | |
770 | REGISTER_CLASS_BODY_PART(index, rwlock_class_array, rwlock_class_max, |
771 | name, name_length) |
772 | |
773 | index= PFS_atomic::add_u32(&rwlock_class_dirty_count, 1); |
774 | |
775 | if (index < rwlock_class_max) |
776 | { |
777 | entry= &rwlock_class_array[index]; |
778 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_RWLOCK); |
779 | entry->m_rwlock_stat.reset(); |
780 | entry->m_event_name_index= rwlock_class_start + index; |
781 | entry->m_singleton= NULL; |
782 | entry->m_enabled= false; /* disabled by default */ |
783 | entry->m_timed= false; |
784 | /* Set user-defined configuration options for this instrument */ |
785 | configure_instr_class(entry); |
786 | PFS_atomic::add_u32(&rwlock_class_allocated_count, 1); |
787 | return (index + 1); |
788 | } |
789 | |
790 | rwlock_class_lost++; |
791 | return 0; |
792 | } |
793 | |
794 | /** |
795 | Register a condition instrumentation metadata. |
796 | @param name the instrumented name |
797 | @param name_length length in bytes of name |
798 | @param flags the instrumentation flags |
799 | @return a condition instrumentation key |
800 | */ |
801 | PFS_sync_key register_cond_class(const char *name, uint name_length, |
802 | int flags) |
803 | { |
804 | /* See comments in register_mutex_class */ |
805 | uint32 index; |
806 | PFS_cond_class *entry; |
807 | |
808 | REGISTER_CLASS_BODY_PART(index, cond_class_array, cond_class_max, |
809 | name, name_length) |
810 | |
811 | index= PFS_atomic::add_u32(&cond_class_dirty_count, 1); |
812 | |
813 | if (index < cond_class_max) |
814 | { |
815 | entry= &cond_class_array[index]; |
816 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_COND); |
817 | entry->m_event_name_index= cond_class_start + index; |
818 | entry->m_singleton= NULL; |
819 | entry->m_enabled= false; /* disabled by default */ |
820 | entry->m_timed= false; |
821 | /* Set user-defined configuration options for this instrument */ |
822 | configure_instr_class(entry); |
823 | PFS_atomic::add_u32(&cond_class_allocated_count, 1); |
824 | return (index + 1); |
825 | } |
826 | |
827 | cond_class_lost++; |
828 | return 0; |
829 | } |
830 | |
831 | #define FIND_CLASS_BODY(KEY, COUNT, ARRAY) \ |
832 | if ((KEY == 0) || (KEY > COUNT)) \ |
833 | return NULL; \ |
834 | return &ARRAY[KEY - 1] |
835 | |
836 | /** |
837 | Find a mutex instrumentation class by key. |
838 | @param key the instrument key |
839 | @return the instrument class, or NULL |
840 | */ |
841 | PFS_mutex_class *find_mutex_class(PFS_sync_key key) |
842 | { |
843 | FIND_CLASS_BODY(key, mutex_class_allocated_count, mutex_class_array); |
844 | } |
845 | |
846 | PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe) |
847 | { |
848 | SANITIZE_ARRAY_BODY(PFS_mutex_class, mutex_class_array, mutex_class_max, unsafe); |
849 | } |
850 | |
851 | /** |
852 | Find a rwlock instrumentation class by key. |
853 | @param key the instrument key |
854 | @return the instrument class, or NULL |
855 | */ |
856 | PFS_rwlock_class *find_rwlock_class(PFS_sync_key key) |
857 | { |
858 | FIND_CLASS_BODY(key, rwlock_class_allocated_count, rwlock_class_array); |
859 | } |
860 | |
861 | PFS_rwlock_class *sanitize_rwlock_class(PFS_rwlock_class *unsafe) |
862 | { |
863 | SANITIZE_ARRAY_BODY(PFS_rwlock_class, rwlock_class_array, rwlock_class_max, unsafe); |
864 | } |
865 | |
866 | /** |
867 | Find a condition instrumentation class by key. |
868 | @param key the instrument key |
869 | @return the instrument class, or NULL |
870 | */ |
871 | PFS_cond_class *find_cond_class(PFS_sync_key key) |
872 | { |
873 | FIND_CLASS_BODY(key, cond_class_allocated_count, cond_class_array); |
874 | } |
875 | |
876 | PFS_cond_class *sanitize_cond_class(PFS_cond_class *unsafe) |
877 | { |
878 | SANITIZE_ARRAY_BODY(PFS_cond_class, cond_class_array, cond_class_max, unsafe); |
879 | } |
880 | |
881 | /** |
882 | Register a thread instrumentation metadata. |
883 | @param name the instrumented name |
884 | @param name_length length in bytes of name |
885 | @param flags the instrumentation flags |
886 | @return a thread instrumentation key |
887 | */ |
888 | PFS_thread_key register_thread_class(const char *name, uint name_length, |
889 | int flags) |
890 | { |
891 | /* See comments in register_mutex_class */ |
892 | uint32 index; |
893 | PFS_thread_class *entry; |
894 | |
895 | for (index= 0; index < thread_class_max; index++) |
896 | { |
897 | entry= &thread_class_array[index]; |
898 | |
899 | if ((entry->m_name_length == name_length) && |
900 | (strncmp(entry->m_name, name, name_length) == 0)) |
901 | return (index + 1); |
902 | } |
903 | |
904 | index= PFS_atomic::add_u32(&thread_class_dirty_count, 1); |
905 | |
906 | if (index < thread_class_max) |
907 | { |
908 | entry= &thread_class_array[index]; |
909 | DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH); |
910 | strncpy(entry->m_name, name, name_length); |
911 | entry->m_name_length= name_length; |
912 | entry->m_enabled= true; |
913 | PFS_atomic::add_u32(&thread_class_allocated_count, 1); |
914 | return (index + 1); |
915 | } |
916 | |
917 | thread_class_lost++; |
918 | return 0; |
919 | } |
920 | |
921 | /** |
922 | Find a thread instrumentation class by key. |
923 | @param key the instrument key |
924 | @return the instrument class, or NULL |
925 | */ |
926 | PFS_thread_class *find_thread_class(PFS_sync_key key) |
927 | { |
928 | FIND_CLASS_BODY(key, thread_class_allocated_count, thread_class_array); |
929 | } |
930 | |
931 | PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe) |
932 | { |
933 | SANITIZE_ARRAY_BODY(PFS_thread_class, thread_class_array, thread_class_max, unsafe); |
934 | } |
935 | |
936 | /** |
937 | Register a file instrumentation metadata. |
938 | @param name the instrumented name |
939 | @param name_length length in bytes of name |
940 | @param flags the instrumentation flags |
941 | @return a file instrumentation key |
942 | */ |
943 | PFS_file_key register_file_class(const char *name, uint name_length, |
944 | int flags) |
945 | { |
946 | /* See comments in register_mutex_class */ |
947 | uint32 index; |
948 | PFS_file_class *entry; |
949 | |
950 | REGISTER_CLASS_BODY_PART(index, file_class_array, file_class_max, |
951 | name, name_length) |
952 | |
953 | index= PFS_atomic::add_u32(&file_class_dirty_count, 1); |
954 | |
955 | if (index < file_class_max) |
956 | { |
957 | entry= &file_class_array[index]; |
958 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_FILE); |
959 | entry->m_event_name_index= file_class_start + index; |
960 | entry->m_singleton= NULL; |
961 | entry->m_enabled= true; /* enabled by default */ |
962 | entry->m_timed= true; |
963 | /* Set user-defined configuration options for this instrument */ |
964 | configure_instr_class(entry); |
965 | PFS_atomic::add_u32(&file_class_allocated_count, 1); |
966 | return (index + 1); |
967 | } |
968 | |
969 | file_class_lost++; |
970 | return 0; |
971 | } |
972 | |
973 | /** |
974 | Register a stage instrumentation metadata. |
975 | @param name the instrumented name |
976 | @param prefix_length length in bytes of the name prefix |
977 | @param name_length length in bytes of name |
978 | @param flags the instrumentation flags |
979 | @return a stage instrumentation key |
980 | */ |
981 | PFS_stage_key register_stage_class(const char *name, |
982 | uint prefix_length, |
983 | uint name_length, |
984 | int flags) |
985 | { |
986 | /* See comments in register_mutex_class */ |
987 | uint32 index; |
988 | PFS_stage_class *entry; |
989 | |
990 | REGISTER_CLASS_BODY_PART(index, stage_class_array, stage_class_max, |
991 | name, name_length) |
992 | |
993 | index= PFS_atomic::add_u32(&stage_class_dirty_count, 1); |
994 | |
995 | if (index < stage_class_max) |
996 | { |
997 | entry= &stage_class_array[index]; |
998 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_STAGE); |
999 | entry->m_prefix_length= prefix_length; |
1000 | entry->m_event_name_index= index; |
1001 | entry->m_enabled= false; /* disabled by default */ |
1002 | entry->m_timed= false; |
1003 | /* Set user-defined configuration options for this instrument */ |
1004 | configure_instr_class(entry); |
1005 | PFS_atomic::add_u32(&stage_class_allocated_count, 1); |
1006 | |
1007 | return (index + 1); |
1008 | } |
1009 | |
1010 | stage_class_lost++; |
1011 | return 0; |
1012 | } |
1013 | |
1014 | /** |
1015 | Register a statement instrumentation metadata. |
1016 | @param name the instrumented name |
1017 | @param name_length length in bytes of name |
1018 | @param flags the instrumentation flags |
1019 | @return a statement instrumentation key |
1020 | */ |
1021 | PFS_statement_key register_statement_class(const char *name, uint name_length, |
1022 | int flags) |
1023 | { |
1024 | /* See comments in register_mutex_class */ |
1025 | uint32 index; |
1026 | PFS_statement_class *entry; |
1027 | |
1028 | REGISTER_CLASS_BODY_PART(index, statement_class_array, statement_class_max, |
1029 | name, name_length) |
1030 | |
1031 | index= PFS_atomic::add_u32(&statement_class_dirty_count, 1); |
1032 | |
1033 | if (index < statement_class_max) |
1034 | { |
1035 | entry= &statement_class_array[index]; |
1036 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_STATEMENT); |
1037 | entry->m_event_name_index= index; |
1038 | entry->m_enabled= true; /* enabled by default */ |
1039 | entry->m_timed= true; |
1040 | /* Set user-defined configuration options for this instrument */ |
1041 | configure_instr_class(entry); |
1042 | PFS_atomic::add_u32(&statement_class_allocated_count, 1); |
1043 | |
1044 | return (index + 1); |
1045 | } |
1046 | |
1047 | statement_class_lost++; |
1048 | return 0; |
1049 | } |
1050 | |
1051 | /** |
1052 | Find a file instrumentation class by key. |
1053 | @param key the instrument key |
1054 | @return the instrument class, or NULL |
1055 | */ |
1056 | PFS_file_class *find_file_class(PFS_file_key key) |
1057 | { |
1058 | FIND_CLASS_BODY(key, file_class_allocated_count, file_class_array); |
1059 | } |
1060 | |
1061 | PFS_file_class *sanitize_file_class(PFS_file_class *unsafe) |
1062 | { |
1063 | SANITIZE_ARRAY_BODY(PFS_file_class, file_class_array, file_class_max, unsafe); |
1064 | } |
1065 | |
1066 | /** |
1067 | Find a stage instrumentation class by key. |
1068 | @param key the instrument key |
1069 | @return the instrument class, or NULL |
1070 | */ |
1071 | PFS_stage_class *find_stage_class(PFS_stage_key key) |
1072 | { |
1073 | FIND_CLASS_BODY(key, stage_class_allocated_count, stage_class_array); |
1074 | } |
1075 | |
1076 | PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe) |
1077 | { |
1078 | SANITIZE_ARRAY_BODY(PFS_stage_class, stage_class_array, stage_class_max, unsafe); |
1079 | } |
1080 | |
1081 | /** |
1082 | Find a statement instrumentation class by key. |
1083 | @param key the instrument key |
1084 | @return the instrument class, or NULL |
1085 | */ |
1086 | PFS_statement_class *find_statement_class(PFS_stage_key key) |
1087 | { |
1088 | FIND_CLASS_BODY(key, statement_class_allocated_count, statement_class_array); |
1089 | } |
1090 | |
1091 | PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe) |
1092 | { |
1093 | SANITIZE_ARRAY_BODY(PFS_statement_class, statement_class_array, statement_class_max, unsafe); |
1094 | } |
1095 | |
1096 | /** |
1097 | Register a socket instrumentation metadata. |
1098 | @param name the instrumented name |
1099 | @param name_length length in bytes of name |
1100 | @param flags the instrumentation flags |
1101 | @return a socket instrumentation key |
1102 | */ |
1103 | PFS_socket_key register_socket_class(const char *name, uint name_length, |
1104 | int flags) |
1105 | { |
1106 | /* See comments in register_mutex_class */ |
1107 | uint32 index; |
1108 | PFS_socket_class *entry; |
1109 | |
1110 | REGISTER_CLASS_BODY_PART(index, socket_class_array, socket_class_max, |
1111 | name, name_length) |
1112 | |
1113 | index= PFS_atomic::add_u32(&socket_class_dirty_count, 1); |
1114 | |
1115 | if (index < socket_class_max) |
1116 | { |
1117 | entry= &socket_class_array[index]; |
1118 | init_instr_class(entry, name, name_length, flags, PFS_CLASS_SOCKET); |
1119 | entry->m_event_name_index= socket_class_start + index; |
1120 | entry->m_singleton= NULL; |
1121 | entry->m_enabled= false; /* disabled by default */ |
1122 | entry->m_timed= false; |
1123 | /* Set user-defined configuration options for this instrument */ |
1124 | configure_instr_class(entry); |
1125 | PFS_atomic::add_u32(&socket_class_allocated_count, 1); |
1126 | return (index + 1); |
1127 | } |
1128 | |
1129 | socket_class_lost++; |
1130 | return 0; |
1131 | } |
1132 | |
1133 | /** |
1134 | Find a socket instrumentation class by key. |
1135 | @param key the instrument key |
1136 | @return the instrument class, or NULL |
1137 | */ |
1138 | PFS_socket_class *find_socket_class(PFS_socket_key key) |
1139 | { |
1140 | FIND_CLASS_BODY(key, socket_class_allocated_count, socket_class_array); |
1141 | } |
1142 | |
1143 | PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe) |
1144 | { |
1145 | SANITIZE_ARRAY_BODY(PFS_socket_class, socket_class_array, socket_class_max, unsafe); |
1146 | } |
1147 | |
1148 | PFS_instr_class *find_table_class(uint index) |
1149 | { |
1150 | if (index == 1) |
1151 | return & global_table_io_class; |
1152 | if (index == 2) |
1153 | return & global_table_lock_class; |
1154 | return NULL; |
1155 | } |
1156 | |
1157 | PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe) |
1158 | { |
1159 | if (likely((& global_table_io_class == unsafe) || |
1160 | (& global_table_lock_class == unsafe))) |
1161 | return unsafe; |
1162 | return NULL; |
1163 | } |
1164 | |
1165 | PFS_instr_class *find_idle_class(uint index) |
1166 | { |
1167 | if (index == 1) |
1168 | return & global_idle_class; |
1169 | return NULL; |
1170 | } |
1171 | |
1172 | PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe) |
1173 | { |
1174 | if (likely(& global_idle_class == unsafe)) |
1175 | return unsafe; |
1176 | return NULL; |
1177 | } |
1178 | |
1179 | static void set_keys(PFS_table_share *pfs, const TABLE_SHARE *share) |
1180 | { |
1181 | uint len; |
1182 | KEY *key_info= share->key_info; |
1183 | PFS_table_key *pfs_key= pfs->m_keys; |
1184 | PFS_table_key *pfs_key_last= pfs->m_keys + share->keys; |
1185 | pfs->m_key_count= share->keys; |
1186 | |
1187 | for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++) |
1188 | { |
1189 | len= (uint)key_info->name.length; |
1190 | memcpy(pfs_key->m_name, key_info->name.str, len); |
1191 | pfs_key->m_name_length= len; |
1192 | } |
1193 | |
1194 | pfs_key_last= pfs->m_keys + MAX_INDEXES; |
1195 | for ( ; pfs_key < pfs_key_last; pfs_key++) |
1196 | pfs_key->m_name_length= 0; |
1197 | } |
1198 | |
1199 | static int compare_keys(PFS_table_share *pfs, const TABLE_SHARE *share) |
1200 | { |
1201 | uint len; |
1202 | KEY *key_info= share->key_info; |
1203 | PFS_table_key *pfs_key= pfs->m_keys; |
1204 | PFS_table_key *pfs_key_last= pfs->m_keys + share->keys; |
1205 | |
1206 | if (pfs->m_key_count != share->keys) |
1207 | return 1; |
1208 | |
1209 | for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++) |
1210 | { |
1211 | len= (uint)key_info->name.length; |
1212 | if (len != pfs_key->m_name_length) |
1213 | return 1; |
1214 | |
1215 | if (memcmp(pfs_key->m_name, key_info->name.str, len) != 0) |
1216 | return 1; |
1217 | } |
1218 | |
1219 | return 0; |
1220 | } |
1221 | |
1222 | /** |
1223 | Find or create a table share instrumentation. |
1224 | @param thread the executing instrumented thread |
1225 | @param temporary true for TEMPORARY TABLE |
1226 | @param share table share |
1227 | @return a table share, or NULL |
1228 | */ |
1229 | PFS_table_share* find_or_create_table_share(PFS_thread *thread, |
1230 | bool temporary, |
1231 | const TABLE_SHARE *share) |
1232 | { |
1233 | /* See comments in register_mutex_class */ |
1234 | PFS_table_share_key key; |
1235 | |
1236 | LF_PINS *pins= get_table_share_hash_pins(thread); |
1237 | if (unlikely(pins == NULL)) |
1238 | { |
1239 | table_share_lost++; |
1240 | return NULL; |
1241 | } |
1242 | |
1243 | const char *schema_name= share->db.str; |
1244 | uint schema_name_length= (uint)share->db.length; |
1245 | const char *table_name= share->table_name.str; |
1246 | uint table_name_length= (uint)share->table_name.length; |
1247 | |
1248 | set_table_share_key(&key, temporary, |
1249 | schema_name, schema_name_length, |
1250 | table_name, table_name_length); |
1251 | |
1252 | PFS_table_share **entry; |
1253 | uint retry_count= 0; |
1254 | const uint retry_max= 3; |
1255 | bool enabled= true; |
1256 | bool timed= true; |
1257 | static uint PFS_ALIGNED table_share_monotonic_index= 0; |
1258 | uint index; |
1259 | uint attempts= 0; |
1260 | PFS_table_share *pfs; |
1261 | |
1262 | search: |
1263 | entry= reinterpret_cast<PFS_table_share**> |
1264 | (lf_hash_search(&table_share_hash, pins, |
1265 | key.m_hash_key, key.m_key_length)); |
1266 | if (entry && (entry != MY_ERRPTR)) |
1267 | { |
1268 | pfs= *entry; |
1269 | pfs->inc_refcount() ; |
1270 | if (compare_keys(pfs, share) != 0) |
1271 | { |
1272 | set_keys(pfs, share); |
1273 | /* FIXME: aggregate to table_share sink ? */ |
1274 | pfs->m_table_stat.fast_reset(); |
1275 | } |
1276 | lf_hash_search_unpin(pins); |
1277 | return pfs; |
1278 | } |
1279 | |
1280 | lf_hash_search_unpin(pins); |
1281 | |
1282 | if (retry_count == 0) |
1283 | { |
1284 | lookup_setup_object(thread, |
1285 | OBJECT_TYPE_TABLE, |
1286 | schema_name, schema_name_length, |
1287 | table_name, table_name_length, |
1288 | &enabled, &timed); |
1289 | /* |
1290 | Even when enabled is false, a record is added in the dictionary: |
1291 | - It makes enabling a table already in the table cache possible, |
1292 | - It improves performances for the next time a TABLE_SHARE is reloaded |
1293 | in the table cache. |
1294 | */ |
1295 | } |
1296 | |
1297 | while (++attempts <= table_share_max) |
1298 | { |
1299 | /* See create_mutex() */ |
1300 | index= PFS_atomic::add_u32(& table_share_monotonic_index, 1) % table_share_max; |
1301 | pfs= table_share_array + index; |
1302 | |
1303 | if (pfs->m_lock.is_free()) |
1304 | { |
1305 | if (pfs->m_lock.free_to_dirty()) |
1306 | { |
1307 | pfs->m_key= key; |
1308 | pfs->m_schema_name= &pfs->m_key.m_hash_key[1]; |
1309 | pfs->m_schema_name_length= schema_name_length; |
1310 | pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 2]; |
1311 | pfs->m_table_name_length= table_name_length; |
1312 | pfs->m_enabled= enabled; |
1313 | pfs->m_timed= timed; |
1314 | pfs->init_refcount(); |
1315 | pfs->m_table_stat.fast_reset(); |
1316 | set_keys(pfs, share); |
1317 | |
1318 | int res; |
1319 | res= lf_hash_insert(&table_share_hash, pins, &pfs); |
1320 | if (likely(res == 0)) |
1321 | { |
1322 | pfs->m_lock.dirty_to_allocated(); |
1323 | return pfs; |
1324 | } |
1325 | |
1326 | pfs->m_lock.dirty_to_free(); |
1327 | |
1328 | if (res > 0) |
1329 | { |
1330 | /* Duplicate insert by another thread */ |
1331 | if (++retry_count > retry_max) |
1332 | { |
1333 | /* Avoid infinite loops */ |
1334 | table_share_lost++; |
1335 | return NULL; |
1336 | } |
1337 | goto search; |
1338 | } |
1339 | |
1340 | /* OOM in lf_hash_insert */ |
1341 | table_share_lost++; |
1342 | return NULL; |
1343 | } |
1344 | } |
1345 | } |
1346 | |
1347 | table_share_lost++; |
1348 | return NULL; |
1349 | } |
1350 | |
1351 | void PFS_table_share::aggregate_io(void) |
1352 | { |
1353 | uint safe_key_count= sanitize_index_count(m_key_count); |
1354 | PFS_table_io_stat *from_stat; |
1355 | PFS_table_io_stat *from_stat_last; |
1356 | PFS_table_io_stat sum_io; |
1357 | |
1358 | /* Aggregate stats for each index, if any */ |
1359 | from_stat= & m_table_stat.m_index_stat[0]; |
1360 | from_stat_last= from_stat + safe_key_count; |
1361 | for ( ; from_stat < from_stat_last ; from_stat++) |
1362 | sum_io.aggregate(from_stat); |
1363 | |
1364 | /* Aggregate stats for the table */ |
1365 | sum_io.aggregate(& m_table_stat.m_index_stat[MAX_INDEXES]); |
1366 | |
1367 | /* Add this table stats to the global sink. */ |
1368 | global_table_io_stat.aggregate(& sum_io); |
1369 | m_table_stat.fast_reset_io(); |
1370 | } |
1371 | |
1372 | void PFS_table_share::aggregate_lock(void) |
1373 | { |
1374 | global_table_lock_stat.aggregate(& m_table_stat.m_lock_stat); |
1375 | m_table_stat.fast_reset_lock(); |
1376 | } |
1377 | |
1378 | void release_table_share(PFS_table_share *pfs) |
1379 | { |
1380 | DBUG_ASSERT(pfs->get_refcount() > 0); |
1381 | pfs->dec_refcount(); |
1382 | } |
1383 | |
1384 | /** |
1385 | Drop the instrumented table share associated with a table. |
1386 | @param thread The running thread |
1387 | @param temporary True for TEMPORARY TABLE |
1388 | @param schema_name The table schema name |
1389 | @param schema_name_length The table schema name length |
1390 | @param table_name The table name |
1391 | @param table_name_length The table name length |
1392 | */ |
1393 | void drop_table_share(PFS_thread *thread, |
1394 | bool temporary, |
1395 | const char *schema_name, uint schema_name_length, |
1396 | const char *table_name, uint table_name_length) |
1397 | { |
1398 | PFS_table_share_key key; |
1399 | LF_PINS* pins= get_table_share_hash_pins(thread); |
1400 | if (unlikely(pins == NULL)) |
1401 | return; |
1402 | set_table_share_key(&key, temporary, schema_name, schema_name_length, |
1403 | table_name, table_name_length); |
1404 | PFS_table_share **entry; |
1405 | entry= reinterpret_cast<PFS_table_share**> |
1406 | (lf_hash_search(&table_share_hash, pins, |
1407 | key.m_hash_key, key.m_key_length)); |
1408 | if (entry && (entry != MY_ERRPTR)) |
1409 | { |
1410 | PFS_table_share *pfs= *entry; |
1411 | lf_hash_delete(&table_share_hash, pins, |
1412 | pfs->m_key.m_hash_key, pfs->m_key.m_key_length); |
1413 | pfs->m_lock.allocated_to_free(); |
1414 | } |
1415 | |
1416 | lf_hash_search_unpin(pins); |
1417 | } |
1418 | |
1419 | /** |
1420 | Sanitize an unsafe table_share pointer. |
1421 | @param unsafe The possibly corrupt pointer. |
1422 | @return A valid table_safe_pointer, or NULL. |
1423 | */ |
1424 | PFS_table_share *sanitize_table_share(PFS_table_share *unsafe) |
1425 | { |
1426 | SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe); |
1427 | } |
1428 | |
1429 | /** Reset the wait statistics per instrument class. */ |
1430 | void reset_events_waits_by_class() |
1431 | { |
1432 | reset_file_class_io(); |
1433 | reset_socket_class_io(); |
1434 | global_idle_stat.reset(); |
1435 | global_table_io_stat.reset(); |
1436 | global_table_lock_stat.reset(); |
1437 | } |
1438 | |
1439 | /** Reset the io statistics per file class. */ |
1440 | void reset_file_class_io(void) |
1441 | { |
1442 | PFS_file_class *pfs= file_class_array; |
1443 | PFS_file_class *pfs_last= file_class_array + file_class_max; |
1444 | |
1445 | for ( ; pfs < pfs_last; pfs++) |
1446 | pfs->m_file_stat.m_io_stat.reset(); |
1447 | } |
1448 | |
1449 | /** Reset the io statistics per socket class. */ |
1450 | void reset_socket_class_io(void) |
1451 | { |
1452 | PFS_socket_class *pfs= socket_class_array; |
1453 | PFS_socket_class *pfs_last= socket_class_array + socket_class_max; |
1454 | |
1455 | for ( ; pfs < pfs_last; pfs++) |
1456 | pfs->m_socket_stat.m_io_stat.reset(); |
1457 | } |
1458 | |
1459 | void update_table_share_derived_flags(PFS_thread *thread) |
1460 | { |
1461 | PFS_table_share *pfs= table_share_array; |
1462 | PFS_table_share *pfs_last= table_share_array + table_share_max; |
1463 | |
1464 | for ( ; pfs < pfs_last; pfs++) |
1465 | { |
1466 | if (pfs->m_lock.is_populated()) |
1467 | pfs->refresh_setup_object_flags(thread); |
1468 | } |
1469 | } |
1470 | |
1471 | /** @} */ |
1472 | |
1473 | |