1 | /* Copyright (c) 2000, 2010, 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 |
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | |
16 | |
17 | /* Write some debug info */ |
18 | |
19 | #include "mariadb.h" |
20 | #include "sql_priv.h" |
21 | #include "unireg.h" |
22 | #include "sql_test.h" |
23 | #include "sql_base.h" |
24 | #include "sql_show.h" // calc_sum_of_all_status |
25 | #include "sql_select.h" |
26 | #include "keycaches.h" |
27 | #include <hash.h> |
28 | #include <thr_alarm.h> |
29 | #if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H) |
30 | #include <malloc.h> |
31 | #elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H) |
32 | #include <sys/malloc.h> |
33 | #endif |
34 | |
35 | #ifdef HAVE_EVENT_SCHEDULER |
36 | #include "events.h" |
37 | #endif |
38 | |
39 | static const char *lock_descriptions[] = |
40 | { |
41 | /* TL_UNLOCK */ "No lock" , |
42 | /* TL_READ_DEFAULT */ NULL, |
43 | /* TL_READ */ "Low priority read lock" , |
44 | /* TL_READ_WITH_SHARED_LOCKS */ "Shared read lock" , |
45 | /* TL_READ_HIGH_PRIORITY */ "High priority read lock" , |
46 | /* TL_READ_NO_INSERT */ "Read lock without concurrent inserts" , |
47 | /* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers" , |
48 | /* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock" , |
49 | /* TL_WRITE_DELAYED */ "Lock used by delayed insert" , |
50 | /* TL_WRITE_DEFAULT */ NULL, |
51 | /* TL_WRITE_LOW_PRIORITY */ "Low priority write lock" , |
52 | /* TL_WRITE */ "High priority write lock" , |
53 | /* TL_WRITE_ONLY */ "Highest priority write lock" |
54 | }; |
55 | |
56 | |
57 | #ifndef DBUG_OFF |
58 | |
59 | void |
60 | print_where(COND *cond,const char *info, enum_query_type query_type) |
61 | { |
62 | char buff[1024]; |
63 | String str(buff,(uint32) sizeof(buff), system_charset_info); |
64 | str.length(0); |
65 | str.extra_allocation(1024); |
66 | if (cond) |
67 | cond->print(&str, query_type); |
68 | |
69 | DBUG_LOCK_FILE; |
70 | (void) fprintf(DBUG_FILE,"\nWHERE:(%s) %p " , info, cond); |
71 | (void) fputs(str.c_ptr_safe(),DBUG_FILE); |
72 | (void) fputc('\n',DBUG_FILE); |
73 | DBUG_UNLOCK_FILE; |
74 | } |
75 | |
76 | #ifdef EXTRA_DEBUG |
77 | /* This is for debugging purposes */ |
78 | static my_bool print_cached_tables_callback(TDC_element *element, |
79 | void *arg __attribute__((unused))) |
80 | { |
81 | TABLE *entry; |
82 | |
83 | mysql_mutex_lock(&element->LOCK_table_share); |
84 | All_share_tables_list::Iterator it(element->all_tables); |
85 | while ((entry= it++)) |
86 | { |
87 | THD *in_use= entry->in_use; |
88 | printf("%-14.14s %-32s%6lu%8ld%6d %s\n" , |
89 | entry->s->db.str, entry->s->table_name.str, |
90 | (ulong) element->version, |
91 | in_use ? (long) in_use->thread_id : (long) 0, |
92 | entry->db_stat ? 1 : 0, |
93 | in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : |
94 | "Not in use" ); |
95 | } |
96 | mysql_mutex_unlock(&element->LOCK_table_share); |
97 | return FALSE; |
98 | } |
99 | |
100 | |
101 | static void print_cached_tables(void) |
102 | { |
103 | compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions)); |
104 | |
105 | /* purecov: begin tested */ |
106 | puts("DB Table Version Thread Open Lock" ); |
107 | |
108 | tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true); |
109 | |
110 | printf("\nCurrent refresh version: %ld\n" , |
111 | (long) tdc_refresh_version()); |
112 | fflush(stdout); |
113 | /* purecov: end */ |
114 | return; |
115 | } |
116 | #endif |
117 | |
118 | |
119 | void TEST_filesort(SORT_FIELD *sortorder,uint s_length) |
120 | { |
121 | char buff[256],buff2[256]; |
122 | String str(buff,sizeof(buff),system_charset_info); |
123 | String out(buff2,sizeof(buff2),system_charset_info); |
124 | const char *sep; |
125 | DBUG_ENTER("TEST_filesort" ); |
126 | |
127 | out.length(0); |
128 | for (sep="" ; s_length-- ; sortorder++, sep=" " ) |
129 | { |
130 | out.append(sep); |
131 | if (sortorder->reverse) |
132 | out.append('-'); |
133 | if (sortorder->field) |
134 | { |
135 | if (sortorder->field->table_name) |
136 | { |
137 | out.append(*sortorder->field->table_name); |
138 | out.append('.'); |
139 | } |
140 | out.append(sortorder->field->field_name.str ? |
141 | sortorder->field->field_name.str : |
142 | "tmp_table_column" ); |
143 | } |
144 | else |
145 | { |
146 | str.length(0); |
147 | sortorder->item->print(&str, QT_ORDINARY); |
148 | out.append(str); |
149 | } |
150 | } |
151 | DBUG_LOCK_FILE; |
152 | (void) fputs("\nInfo about FILESORT\n" ,DBUG_FILE); |
153 | fprintf(DBUG_FILE,"Sortorder: %s\n" ,out.c_ptr_safe()); |
154 | DBUG_UNLOCK_FILE; |
155 | DBUG_VOID_RETURN; |
156 | } |
157 | |
158 | |
159 | void |
160 | TEST_join(JOIN *join) |
161 | { |
162 | uint ref; |
163 | int i; |
164 | List_iterator<JOIN_TAB_RANGE> it(join->join_tab_ranges); |
165 | JOIN_TAB_RANGE *jt_range; |
166 | DBUG_ENTER("TEST_join" ); |
167 | |
168 | DBUG_LOCK_FILE; |
169 | (void) fputs("\nInfo about JOIN\n" ,DBUG_FILE); |
170 | while ((jt_range= it++)) |
171 | { |
172 | /* |
173 | Assemble results of all the calls to full_name() first, |
174 | in order not to garble the tabular output below. |
175 | */ |
176 | String ref_key_parts[MAX_TABLES]; |
177 | int tables_in_range= (int)(jt_range->end - jt_range->start); |
178 | for (i= 0; i < tables_in_range; i++) |
179 | { |
180 | JOIN_TAB *tab= jt_range->start + i; |
181 | for (ref= 0; ref < tab->ref.key_parts; ref++) |
182 | { |
183 | ref_key_parts[i].append(tab->ref.items[ref]->full_name()); |
184 | ref_key_parts[i].append(" " ); |
185 | } |
186 | } |
187 | |
188 | for (i= 0; i < tables_in_range; i++) |
189 | { |
190 | JOIN_TAB *tab= jt_range->start + i; |
191 | TABLE *form=tab->table; |
192 | char key_map_buff[128]; |
193 | fprintf(DBUG_FILE,"%-16.16s type: %-7s q_keys: %s refs: %d key: %d len: %d\n" , |
194 | form->alias.c_ptr(), |
195 | join_type_str[tab->type], |
196 | tab->keys.print(key_map_buff), |
197 | tab->ref.key_parts, |
198 | tab->ref.key, |
199 | tab->ref.key_length); |
200 | if (tab->select) |
201 | { |
202 | char buf[MAX_KEY/8+1]; |
203 | if (tab->use_quick == 2) |
204 | fprintf(DBUG_FILE, |
205 | " quick select checked for each record (keys: %s)\n" , |
206 | tab->select->quick_keys.print(buf)); |
207 | else if (tab->select->quick) |
208 | { |
209 | fprintf(DBUG_FILE, " quick select used:\n" ); |
210 | tab->select->quick->dbug_dump(18, FALSE); |
211 | } |
212 | else |
213 | (void)fputs(" select used\n" ,DBUG_FILE); |
214 | } |
215 | if (tab->ref.key_parts) |
216 | { |
217 | fprintf(DBUG_FILE, |
218 | " refs: %s\n" , ref_key_parts[i].c_ptr_safe()); |
219 | } |
220 | } |
221 | (void)fputs("\n" ,DBUG_FILE); |
222 | } |
223 | DBUG_UNLOCK_FILE; |
224 | DBUG_VOID_RETURN; |
225 | } |
226 | |
227 | |
228 | #define FT_KEYPART (MAX_FIELDS+10) |
229 | |
230 | static void print_keyuse(KEYUSE *keyuse) |
231 | { |
232 | char buff[256]; |
233 | char buf2[64]; |
234 | const char *fieldname; |
235 | JOIN_TAB *join_tab= keyuse->table->reginfo.join_tab; |
236 | KEY *key_info= join_tab->get_keyinfo_by_key_no(keyuse->key); |
237 | String str(buff,(uint32) sizeof(buff), system_charset_info); |
238 | str.length(0); |
239 | keyuse->val->print(&str, QT_ORDINARY); |
240 | str.append('\0'); |
241 | if (keyuse->is_for_hash_join()) |
242 | fieldname= keyuse->table->field[keyuse->keypart]->field_name.str; |
243 | else if (keyuse->keypart == FT_KEYPART) |
244 | fieldname= "FT_KEYPART" ; |
245 | else |
246 | fieldname= key_info->key_part[keyuse->keypart].field->field_name.str; |
247 | ll2str(keyuse->used_tables, buf2, 16, 0); |
248 | fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s " |
249 | "ref_table_rows: %lu keypart_map: %0lx\n" , |
250 | keyuse->table->alias.c_ptr(), fieldname, str.ptr(), |
251 | (uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows, |
252 | (ulong) keyuse->keypart_map); |
253 | } |
254 | |
255 | |
256 | /* purecov: begin inspected */ |
257 | void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array) |
258 | { |
259 | DBUG_LOCK_FILE; |
260 | fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n" , keyuse_array->elements); |
261 | for(uint i=0; i < keyuse_array->elements; i++) |
262 | print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i)); |
263 | DBUG_UNLOCK_FILE; |
264 | } |
265 | |
266 | |
267 | /* |
268 | Print the current state during query optimization. |
269 | |
270 | SYNOPSIS |
271 | print_plan() |
272 | join pointer to the structure providing all context info for |
273 | the query |
274 | read_time the cost of the best partial plan |
275 | record_count estimate for the number of records returned by the best |
276 | partial plan |
277 | idx length of the partial QEP in 'join->positions'; |
278 | also an index in the array 'join->best_ref'; |
279 | info comment string to appear above the printout |
280 | |
281 | DESCRIPTION |
282 | This function prints to the log file DBUG_FILE the members of 'join' that |
283 | are used during query optimization (join->positions, join->best_positions, |
284 | and join->best_ref) and few other related variables (read_time, |
285 | record_count). |
286 | Useful to trace query optimizer functions. |
287 | |
288 | RETURN |
289 | None |
290 | */ |
291 | |
292 | void |
293 | print_plan(JOIN* join, uint idx, double record_count, double read_time, |
294 | double current_read_time, const char *info) |
295 | { |
296 | uint i; |
297 | POSITION pos; |
298 | JOIN_TAB *join_table; |
299 | JOIN_TAB **plan_nodes; |
300 | TABLE* table; |
301 | |
302 | if (info == 0) |
303 | info= "" ; |
304 | |
305 | DBUG_LOCK_FILE; |
306 | if (join->best_read == DBL_MAX) |
307 | { |
308 | fprintf(DBUG_FILE, |
309 | "%s; idx: %u best: DBL_MAX atime: %g itime: %g count: %g\n" , |
310 | info, idx, current_read_time, read_time, record_count); |
311 | } |
312 | else |
313 | { |
314 | fprintf(DBUG_FILE, |
315 | "%s; idx :%u best: %g accumulated: %g increment: %g count: %g\n" , |
316 | info, idx, join->best_read, current_read_time, read_time, |
317 | record_count); |
318 | } |
319 | |
320 | /* Print the tables in JOIN->positions */ |
321 | fputs(" POSITIONS: " , DBUG_FILE); |
322 | for (i= 0; i < idx ; i++) |
323 | { |
324 | pos = join->positions[i]; |
325 | table= pos.table->table; |
326 | if (table) |
327 | fputs(table->s->table_name.str, DBUG_FILE); |
328 | fputc(' ', DBUG_FILE); |
329 | } |
330 | fputc('\n', DBUG_FILE); |
331 | |
332 | /* |
333 | Print the tables in JOIN->best_positions only if at least one complete plan |
334 | has been found. An indicator for this is the value of 'join->best_read'. |
335 | */ |
336 | if (join->best_read < DBL_MAX) |
337 | { |
338 | fputs("BEST_POSITIONS: " , DBUG_FILE); |
339 | for (i= 0; i < idx ; i++) |
340 | { |
341 | pos= join->best_positions[i]; |
342 | table= pos.table->table; |
343 | if (table) |
344 | fputs(table->s->table_name.str, DBUG_FILE); |
345 | fputc(' ', DBUG_FILE); |
346 | } |
347 | } |
348 | fputc('\n', DBUG_FILE); |
349 | |
350 | /* Print the tables in JOIN->best_ref */ |
351 | fputs(" BEST_REF: " , DBUG_FILE); |
352 | for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++) |
353 | { |
354 | join_table= (*plan_nodes); |
355 | fputs(join_table->table->s->table_name.str, DBUG_FILE); |
356 | fprintf(DBUG_FILE, "(%lu,%lu,%lu)" , |
357 | (ulong) join_table->found_records, |
358 | (ulong) join_table->records, |
359 | (ulong) join_table->read_time); |
360 | fputc(' ', DBUG_FILE); |
361 | } |
362 | fputc('\n', DBUG_FILE); |
363 | |
364 | DBUG_UNLOCK_FILE; |
365 | } |
366 | |
367 | |
368 | void print_sjm(SJ_MATERIALIZATION_INFO *sjm) |
369 | { |
370 | DBUG_LOCK_FILE; |
371 | fprintf(DBUG_FILE, "\nsemi-join nest{\n" ); |
372 | fprintf(DBUG_FILE, " tables { \n" ); |
373 | for (uint i= 0;i < sjm->tables; i++) |
374 | { |
375 | fprintf(DBUG_FILE, " %s%s\n" , |
376 | sjm->positions[i].table->table->alias.c_ptr(), |
377 | (i == sjm->tables -1)? "" : "," ); |
378 | } |
379 | fprintf(DBUG_FILE, " }\n" ); |
380 | fprintf(DBUG_FILE, " materialize_cost= %g\n" , |
381 | sjm->materialization_cost.total_cost()); |
382 | fprintf(DBUG_FILE, " rows= %g\n" , sjm->rows); |
383 | fprintf(DBUG_FILE, "}\n" ); |
384 | DBUG_UNLOCK_FILE; |
385 | } |
386 | /* purecov: end */ |
387 | |
388 | /* |
389 | Debugging help: force List<...>::elem function not be removed as unused. |
390 | */ |
391 | Item* (List<Item>:: *dbug_list_item_elem_ptr)(uint)= &List<Item>::elem; |
392 | Item_equal* (List<Item_equal>:: *dbug_list_item_equal_elem_ptr)(uint)= |
393 | &List<Item_equal>::elem; |
394 | TABLE_LIST* (List<TABLE_LIST>:: *dbug_list_table_list_elem_ptr)(uint) = |
395 | &List<TABLE_LIST>::elem; |
396 | |
397 | #endif |
398 | |
399 | typedef struct st_debug_lock |
400 | { |
401 | ulong thread_id; |
402 | char table_name[FN_REFLEN]; |
403 | bool waiting; |
404 | const char *lock_text; |
405 | enum thr_lock_type type; |
406 | } TABLE_LOCK_INFO; |
407 | |
408 | C_MODE_START |
409 | static int dl_compare(const void *p1, const void *p2) |
410 | { |
411 | TABLE_LOCK_INFO *a, *b; |
412 | |
413 | a= (TABLE_LOCK_INFO *) p1; |
414 | b= (TABLE_LOCK_INFO *) p2; |
415 | |
416 | if (a->thread_id > b->thread_id) |
417 | return 1; |
418 | if (a->thread_id < b->thread_id) |
419 | return -1; |
420 | if (a->waiting == b->waiting) |
421 | return 0; |
422 | else if (a->waiting) |
423 | return -1; |
424 | return 1; |
425 | } |
426 | C_MODE_END |
427 | |
428 | |
429 | static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, |
430 | bool wait, const char *text) |
431 | { |
432 | if (data) |
433 | { |
434 | TABLE *table=(TABLE *)data->debug_print_param; |
435 | if (table && table->s->tmp_table == NO_TMP_TABLE) |
436 | { |
437 | TABLE_LOCK_INFO table_lock_info; |
438 | table_lock_info.thread_id= (ulong)table->in_use->thread_id; |
439 | memcpy(table_lock_info.table_name, table->s->table_cache_key.str, |
440 | table->s->table_cache_key.length); |
441 | table_lock_info.table_name[strlen(table_lock_info.table_name)]='.'; |
442 | table_lock_info.waiting=wait; |
443 | table_lock_info.lock_text=text; |
444 | // lock_type is also obtainable from THR_LOCK_DATA |
445 | table_lock_info.type=table->reginfo.lock_type; |
446 | (void) push_dynamic(ar,(uchar*) &table_lock_info); |
447 | } |
448 | } |
449 | } |
450 | |
451 | |
452 | /* |
453 | Regarding MERGE tables: |
454 | |
455 | For now, the best option is to use the common TABLE *pointer for all |
456 | cases; The drawback is that for MERGE tables we will see many locks |
457 | for the merge tables even if some of them are for individual tables. |
458 | |
459 | The way to solve this is to add to 'THR_LOCK' structure a pointer to |
460 | the filename and use this when printing the data. |
461 | (We can for now ignore this and just print the same name for all merge |
462 | table parts; Please add the above as a comment to the display_lock |
463 | function so that we can easily add this if we ever need this. |
464 | */ |
465 | |
466 | static void display_table_locks(void) |
467 | { |
468 | LIST *list; |
469 | void *saved_base; |
470 | DYNAMIC_ARRAY saved_table_locks; |
471 | |
472 | (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), |
473 | tc_records() + 20, 50, MYF(0)); |
474 | mysql_mutex_lock(&THR_LOCK_lock); |
475 | for (list= thr_lock_thread_list; list; list= list_rest(list)) |
476 | { |
477 | THR_LOCK *lock=(THR_LOCK*) list->data; |
478 | |
479 | mysql_mutex_lock(&lock->mutex); |
480 | push_locks_into_array(&saved_table_locks, lock->write.data, FALSE, |
481 | "Locked - write" ); |
482 | push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE, |
483 | "Waiting - write" ); |
484 | push_locks_into_array(&saved_table_locks, lock->read.data, FALSE, |
485 | "Locked - read" ); |
486 | push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE, |
487 | "Waiting - read" ); |
488 | mysql_mutex_unlock(&lock->mutex); |
489 | } |
490 | mysql_mutex_unlock(&THR_LOCK_lock); |
491 | |
492 | if (!saved_table_locks.elements) |
493 | goto end; |
494 | |
495 | saved_base= dynamic_element(&saved_table_locks, 0, TABLE_LOCK_INFO *); |
496 | my_qsort(saved_base, saved_table_locks.elements, sizeof(TABLE_LOCK_INFO), |
497 | dl_compare); |
498 | freeze_size(&saved_table_locks); |
499 | |
500 | puts("\nThread database.table_name Locked/Waiting Lock_type\n" ); |
501 | |
502 | unsigned int i; |
503 | for (i=0 ; i < saved_table_locks.elements ; i++) |
504 | { |
505 | TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*); |
506 | printf("%-8ld%-28.28s%-22s%s\n" , |
507 | dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]); |
508 | } |
509 | puts("\n\n" ); |
510 | end: |
511 | delete_dynamic(&saved_table_locks); |
512 | } |
513 | |
514 | C_MODE_START |
515 | static int print_key_cache_status(const char *name, KEY_CACHE *key_cache, |
516 | void *unused __attribute__((unused))) |
517 | { |
518 | char llbuff1[22]; |
519 | char llbuff2[22]; |
520 | char llbuff3[22]; |
521 | char llbuff4[22]; |
522 | |
523 | if (!key_cache->key_cache_inited) |
524 | { |
525 | printf("%s: Not in use\n" , name); |
526 | } |
527 | else |
528 | { |
529 | KEY_CACHE_STATISTICS stats; |
530 | get_key_cache_statistics(key_cache, 0, &stats); |
531 | |
532 | printf("%s\n\ |
533 | Buffer_size: %10lu\n\ |
534 | Block_size: %10lu\n\ |
535 | Division_limit: %10lu\n\ |
536 | Age_threshold: %10lu\n\ |
537 | Partitions: %10lu\n\ |
538 | blocks used: %10lu\n\ |
539 | not flushed: %10lu\n\ |
540 | w_requests: %10s\n\ |
541 | writes: %10s\n\ |
542 | r_requests: %10s\n\ |
543 | reads: %10s\n\n" , |
544 | name, |
545 | (ulong)key_cache->param_buff_size, |
546 | (ulong)key_cache->param_block_size, |
547 | (ulong)key_cache->param_division_limit, |
548 | (ulong)key_cache->param_age_threshold, |
549 | (ulong)key_cache->param_partitions, |
550 | (ulong)stats.blocks_used, |
551 | (ulong)stats.blocks_changed, |
552 | llstr(stats.write_requests,llbuff1), |
553 | llstr(stats.writes,llbuff2), |
554 | llstr(stats.read_requests,llbuff3), |
555 | llstr(stats.reads,llbuff4)); |
556 | } |
557 | return 0; |
558 | } |
559 | C_MODE_END |
560 | |
561 | |
562 | void mysql_print_status() |
563 | { |
564 | char current_dir[FN_REFLEN]; |
565 | STATUS_VAR tmp; |
566 | uint count; |
567 | |
568 | count= calc_sum_of_all_status(&tmp); |
569 | printf("\nStatus information:\n\n" ); |
570 | (void) my_getwd(current_dir, sizeof(current_dir),MYF(0)); |
571 | printf("Current dir: %s\n" , current_dir); |
572 | printf("Running threads: %d Cached threads: %lu Stack size: %ld\n" , |
573 | count, cached_thread_count, |
574 | (long) my_thread_stack_size); |
575 | #ifdef EXTRA_DEBUG |
576 | thr_print_locks(); // Write some debug info |
577 | print_cached_tables(); |
578 | #endif |
579 | /* Print key cache status */ |
580 | puts("\nKey caches:" ); |
581 | process_key_caches(print_key_cache_status, 0); |
582 | printf("\nhandler status:\n\ |
583 | read_key: %10lu\n\ |
584 | read_next: %10lu\n\ |
585 | read_rnd %10lu\n\ |
586 | read_first: %10lu\n\ |
587 | write: %10lu\n\ |
588 | delete %10lu\n\ |
589 | update: %10lu\n" , |
590 | tmp.ha_read_key_count, |
591 | tmp.ha_read_next_count, |
592 | tmp.ha_read_rnd_count, |
593 | tmp.ha_read_first_count, |
594 | tmp.ha_write_count, |
595 | tmp.ha_delete_count, |
596 | tmp.ha_update_count); |
597 | printf("\nTable status:\n\ |
598 | Opened tables: %10lu\n\ |
599 | Open tables: %10lu\n\ |
600 | Open files: %10lu\n\ |
601 | Open streams: %10lu\n" , |
602 | tmp.opened_tables, |
603 | (ulong) tc_records(), |
604 | (ulong) my_file_opened, |
605 | (ulong) my_stream_opened); |
606 | |
607 | #ifndef DONT_USE_THR_ALARM |
608 | ALARM_INFO alarm_info; |
609 | thr_alarm_info(&alarm_info); |
610 | printf("\nAlarm status:\n\ |
611 | Active alarms: %u\n\ |
612 | Max used alarms: %u\n\ |
613 | Next alarm time: %lu\n" , |
614 | alarm_info.active_alarms, |
615 | alarm_info.max_used_alarms, |
616 | (ulong)alarm_info.next_alarm_time); |
617 | #endif |
618 | display_table_locks(); |
619 | #ifdef HAVE_MALLINFO |
620 | struct mallinfo info= mallinfo(); |
621 | char llbuff[10][22]; |
622 | printf("\nMemory status:\n\ |
623 | Non-mmapped space allocated from system: %s\n\ |
624 | Number of free chunks: %lu\n\ |
625 | Number of fastbin blocks: %lu\n\ |
626 | Number of mmapped regions: %lu\n\ |
627 | Space in mmapped regions: %s\n\ |
628 | Maximum total allocated space: %s\n\ |
629 | Space available in freed fastbin blocks: %s\n\ |
630 | Total allocated space: %s\n\ |
631 | Total free space: %s\n\ |
632 | Top-most, releasable space: %s\n\ |
633 | Estimated memory (with thread stack): %s\n\ |
634 | Global memory allocated by server: %s\n\ |
635 | Memory allocated by threads: %s\n" , |
636 | llstr(info.arena, llbuff[0]), |
637 | (ulong) info.ordblks, |
638 | (ulong) info.smblks, |
639 | (ulong) info.hblks, |
640 | llstr(info.hblkhd, llbuff[1]), |
641 | llstr(info.usmblks, llbuff[2]), |
642 | llstr(info.fsmblks, llbuff[3]), |
643 | llstr(info.uordblks, llbuff[4]), |
644 | llstr(info.fordblks, llbuff[5]), |
645 | llstr(info.keepcost, llbuff[6]), |
646 | llstr((count + cached_thread_count)* my_thread_stack_size + info.hblkhd + info.arena, llbuff[7]), |
647 | llstr(tmp.global_memory_used, llbuff[8]), |
648 | llstr(tmp.local_memory_used, llbuff[9])); |
649 | |
650 | #endif |
651 | |
652 | #ifdef HAVE_EVENT_SCHEDULER |
653 | Events::dump_internal_status(); |
654 | #endif |
655 | puts("" ); |
656 | fflush(stdout); |
657 | } |
658 | |