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-1335 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 "my_json_writer.h"
28 #include <hash.h>
29 #include <thr_alarm.h>
30 #include "sql_connect.h"
31 #include "thread_cache.h"
32 #if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
33 #include <malloc.h>
34 #elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H)
35 #include <sys/malloc.h>
36 #elif defined(HAVE_MALLOC_ZONE)
37 #include <malloc/malloc.h>
38 #endif
39
40 #ifdef HAVE_EVENT_SCHEDULER
41 #include "events.h"
42 #endif
43
44 #define FT_KEYPART (MAX_FIELDS+10)
45
46 static const char *lock_descriptions[] =
47 {
48 /* TL_UNLOCK */ "No lock",
49 /* TL_READ_DEFAULT */ NULL,
50 /* TL_READ */ "Low priority read lock",
51 /* TL_READ_WITH_SHARED_LOCKS */ "Shared read lock",
52 /* TL_READ_HIGH_PRIORITY */ "High priority read lock",
53 /* TL_READ_NO_INSERT */ "Read lock without concurrent inserts",
54 /* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers",
55 /* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock",
56 /* TL_WRITE_DELAYED */ "Lock used by delayed insert",
57 /* TL_WRITE_DEFAULT */ NULL,
58 /* TL_WRITE_LOW_PRIORITY */ "Low priority write lock",
59 /* TL_WRITE */ "High priority write lock",
60 /* TL_WRITE_ONLY */ "Highest priority write lock"
61 };
62
63
64 #ifndef DBUG_OFF
65
66 void
print_where(COND * cond,const char * info,enum_query_type query_type)67 print_where(COND *cond,const char *info, enum_query_type query_type)
68 {
69 char buff[1024];
70 String str(buff,(uint32) sizeof(buff), system_charset_info);
71 str.length(0);
72 str.extra_allocation(1024);
73 if (cond)
74 cond->print(&str, query_type);
75
76 DBUG_LOCK_FILE;
77 (void) fprintf(DBUG_FILE,"\nWHERE:(%s) %p ", info, cond);
78 (void) fputs(str.c_ptr_safe(),DBUG_FILE);
79 (void) fputc('\n',DBUG_FILE);
80 DBUG_UNLOCK_FILE;
81 }
82
83 #ifdef EXTRA_DEBUG
84 /* This is for debugging purposes */
print_cached_tables_callback(TDC_element * element,void * arg)85 static my_bool print_cached_tables_callback(TDC_element *element,
86 void *arg __attribute__((unused)))
87 {
88 TABLE *entry;
89
90 mysql_mutex_lock(&element->LOCK_table_share);
91 All_share_tables_list::Iterator it(element->all_tables);
92 while ((entry= it++))
93 {
94 THD *in_use= entry->in_use;
95 printf("%-14.14s %-32s%8ld%6d %s\n",
96 entry->s->db.str, entry->s->table_name.str,
97 in_use ? (long) in_use->thread_id : (long) 0,
98 entry->db_stat ? 1 : 0,
99 in_use ? lock_descriptions[(int)entry->reginfo.lock_type] :
100 "Not in use");
101 }
102 mysql_mutex_unlock(&element->LOCK_table_share);
103 return FALSE;
104 }
105
106
print_cached_tables(void)107 static void print_cached_tables(void)
108 {
109 compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions));
110
111 /* purecov: begin tested */
112 puts("DB Table Version Thread Open Lock");
113
114 tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true);
115
116 fflush(stdout);
117 /* purecov: end */
118 return;
119 }
120 #endif
121
122
TEST_filesort(SORT_FIELD * sortorder,uint s_length)123 void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
124 {
125 char buff[256],buff2[256];
126 String str(buff,sizeof(buff),system_charset_info);
127 String out(buff2,sizeof(buff2),system_charset_info);
128 const char *sep;
129 DBUG_ENTER("TEST_filesort");
130
131 out.length(0);
132 for (sep=""; s_length-- ; sortorder++, sep=" ")
133 {
134 out.append(sep);
135 if (sortorder->reverse)
136 out.append('-');
137 if (sortorder->field)
138 {
139 if (sortorder->field->table_name)
140 {
141 out.append(*sortorder->field->table_name);
142 out.append('.');
143 }
144 out.append(sortorder->field->field_name.str ?
145 sortorder->field->field_name.str :
146 "tmp_table_column");
147 }
148 else
149 {
150 str.length(0);
151 sortorder->item->print(&str, QT_ORDINARY);
152 out.append(str);
153 }
154 }
155 DBUG_LOCK_FILE;
156 (void) fputs("\nInfo about FILESORT\n",DBUG_FILE);
157 fprintf(DBUG_FILE,"Sortorder: %s\n",out.c_ptr_safe());
158 DBUG_UNLOCK_FILE;
159 DBUG_VOID_RETURN;
160 }
161
162
163 void
TEST_join(JOIN * join)164 TEST_join(JOIN *join)
165 {
166 uint ref;
167 int i;
168 List_iterator<JOIN_TAB_RANGE> it(join->join_tab_ranges);
169 JOIN_TAB_RANGE *jt_range;
170 DBUG_ENTER("TEST_join");
171
172 DBUG_LOCK_FILE;
173 (void) fputs("\nInfo about JOIN\n",DBUG_FILE);
174 while ((jt_range= it++))
175 {
176 /*
177 Assemble results of all the calls to full_name() first,
178 in order not to garble the tabular output below.
179 */
180 String ref_key_parts[MAX_TABLES];
181 int tables_in_range= (int)(jt_range->end - jt_range->start);
182 for (i= 0; i < tables_in_range; i++)
183 {
184 JOIN_TAB *tab= jt_range->start + i;
185 for (ref= 0; ref < tab->ref.key_parts; ref++)
186 {
187 ref_key_parts[i].append(tab->ref.items[ref]->full_name());
188 ref_key_parts[i].append(" ");
189 }
190 }
191
192 for (i= 0; i < tables_in_range; i++)
193 {
194 JOIN_TAB *tab= jt_range->start + i;
195 TABLE *form=tab->table;
196 char key_map_buff[128];
197 fprintf(DBUG_FILE,"%-16.16s type: %-7s q_keys: %s refs: %d key: %d len: %d\n",
198 form->alias.c_ptr(),
199 join_type_str[tab->type],
200 tab->keys.print(key_map_buff),
201 tab->ref.key_parts,
202 tab->ref.key,
203 tab->ref.key_length);
204 if (tab->select)
205 {
206 char buf[MAX_KEY/8+1];
207 if (tab->use_quick == 2)
208 fprintf(DBUG_FILE,
209 " quick select checked for each record (keys: %s)\n",
210 tab->select->quick_keys.print(buf));
211 else if (tab->select->quick)
212 {
213 fprintf(DBUG_FILE, " quick select used:\n");
214 tab->select->quick->dbug_dump(18, FALSE);
215 }
216 else
217 (void)fputs(" select used\n",DBUG_FILE);
218 }
219 if (tab->ref.key_parts)
220 {
221 fprintf(DBUG_FILE,
222 " refs: %s\n", ref_key_parts[i].c_ptr_safe());
223 }
224 }
225 (void)fputs("\n",DBUG_FILE);
226 }
227 DBUG_UNLOCK_FILE;
228 DBUG_VOID_RETURN;
229 }
230
231
print_keyuse(KEYUSE * keyuse)232 static void print_keyuse(KEYUSE *keyuse)
233 {
234 char buff[256];
235 char buf2[64];
236 const char *fieldname;
237 JOIN_TAB *join_tab= keyuse->table->reginfo.join_tab;
238 KEY *key_info= join_tab->get_keyinfo_by_key_no(keyuse->key);
239 String str(buff,(uint32) sizeof(buff), system_charset_info);
240 str.length(0);
241 keyuse->val->print(&str, QT_ORDINARY);
242 str.append('\0');
243 if (keyuse->is_for_hash_join())
244 fieldname= keyuse->table->field[keyuse->keypart]->field_name.str;
245 else if (keyuse->keypart == FT_KEYPART)
246 fieldname= "FT_KEYPART";
247 else
248 fieldname= key_info->key_part[keyuse->keypart].field->field_name.str;
249 ll2str(keyuse->used_tables, buf2, 16, 0);
250 fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s "
251 "ref_table_rows: %lu keypart_map: %0lx\n",
252 keyuse->table->alias.c_ptr(), fieldname, str.ptr(),
253 (uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows,
254 (ulong) keyuse->keypart_map);
255 }
256
257
258 /* purecov: begin inspected */
print_keyuse_array(DYNAMIC_ARRAY * keyuse_array)259 void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array)
260 {
261 DBUG_LOCK_FILE;
262 fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements);
263 for(uint i=0; i < keyuse_array->elements; i++)
264 print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i));
265 DBUG_UNLOCK_FILE;
266 }
267
268 /*
269 Print the current state during query optimization.
270
271 SYNOPSIS
272 print_plan()
273 join pointer to the structure providing all context info for
274 the query
275 read_time the cost of the best partial plan
276 record_count estimate for the number of records returned by the best
277 partial plan
278 idx length of the partial QEP in 'join->positions';
279 also an index in the array 'join->best_ref';
280 info comment string to appear above the printout
281
282 DESCRIPTION
283 This function prints to the log file DBUG_FILE the members of 'join' that
284 are used during query optimization (join->positions, join->best_positions,
285 and join->best_ref) and few other related variables (read_time,
286 record_count).
287 Useful to trace query optimizer functions.
288
289 RETURN
290 None
291 */
292
293 void
print_plan(JOIN * join,uint idx,double record_count,double read_time,double current_read_time,const char * info)294 print_plan(JOIN* join, uint idx, double record_count, double read_time,
295 double current_read_time, const char *info)
296 {
297 uint i;
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 POSITION *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 POSITION *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
print_sjm(SJ_MATERIALIZATION_INFO * sjm)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
dl_compare(const void * p1,const void * p2)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
push_locks_into_array(DYNAMIC_ARRAY * ar,THR_LOCK_DATA * data,bool wait,const char * text)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
display_table_locks(void)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(key_memory_locked_thread_list,
473 &saved_table_locks, sizeof(TABLE_LOCK_INFO),
474 tc_records() + 20, 50, MYF(0));
475 mysql_mutex_lock(&THR_LOCK_lock);
476 for (list= thr_lock_thread_list; list; list= list_rest(list))
477 {
478 THR_LOCK *lock=(THR_LOCK*) list->data;
479
480 mysql_mutex_lock(&lock->mutex);
481 push_locks_into_array(&saved_table_locks, lock->write.data, FALSE,
482 "Locked - write");
483 push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE,
484 "Waiting - write");
485 push_locks_into_array(&saved_table_locks, lock->read.data, FALSE,
486 "Locked - read");
487 push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE,
488 "Waiting - read");
489 mysql_mutex_unlock(&lock->mutex);
490 }
491 mysql_mutex_unlock(&THR_LOCK_lock);
492
493 if (!saved_table_locks.elements)
494 goto end;
495
496 saved_base= dynamic_element(&saved_table_locks, 0, TABLE_LOCK_INFO *);
497 my_qsort(saved_base, saved_table_locks.elements, sizeof(TABLE_LOCK_INFO),
498 dl_compare);
499 freeze_size(&saved_table_locks);
500
501 puts("\nThread database.table_name Locked/Waiting Lock_type\n");
502
503 unsigned int i;
504 for (i=0 ; i < saved_table_locks.elements ; i++)
505 {
506 TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*);
507 printf("%-8ld%-28.28s%-22s%s\n",
508 dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]);
509 }
510 puts("\n\n");
511 end:
512 delete_dynamic(&saved_table_locks);
513 }
514
515 C_MODE_START
print_key_cache_status(const char * name,KEY_CACHE * key_cache,void * unused)516 static int print_key_cache_status(const char *name, KEY_CACHE *key_cache,
517 void *unused __attribute__((unused)))
518 {
519 char llbuff1[22];
520 char llbuff2[22];
521 char llbuff3[22];
522 char llbuff4[22];
523
524 if (!key_cache->key_cache_inited)
525 {
526 printf("%s: Not in use\n", name);
527 }
528 else
529 {
530 KEY_CACHE_STATISTICS stats;
531 get_key_cache_statistics(key_cache, 0, &stats);
532
533 printf("%s\n\
534 Buffer_size: %10lu\n\
535 Block_size: %10lu\n\
536 Division_limit: %10lu\n\
537 Age_threshold: %10lu\n\
538 Partitions: %10lu\n\
539 blocks used: %10lu\n\
540 not flushed: %10lu\n\
541 w_requests: %10s\n\
542 writes: %10s\n\
543 r_requests: %10s\n\
544 reads: %10s\n\n",
545 name,
546 (ulong)key_cache->param_buff_size,
547 (ulong)key_cache->param_block_size,
548 (ulong)key_cache->param_division_limit,
549 (ulong)key_cache->param_age_threshold,
550 (ulong)key_cache->param_partitions,
551 (ulong)stats.blocks_used,
552 (ulong)stats.blocks_changed,
553 llstr(stats.write_requests,llbuff1),
554 llstr(stats.writes,llbuff2),
555 llstr(stats.read_requests,llbuff3),
556 llstr(stats.reads,llbuff4));
557 }
558 return 0;
559 }
560 C_MODE_END
561
562
mysql_print_status()563 void mysql_print_status()
564 {
565 char current_dir[FN_REFLEN];
566 STATUS_VAR tmp;
567 uint count;
568
569 tmp= global_status_var;
570 count= calc_sum_of_all_status(&tmp);
571 printf("\nStatus information:\n\n");
572 (void) my_getwd(current_dir, sizeof(current_dir),MYF(0));
573 printf("Current dir: %s\n", current_dir);
574 printf("Running threads: %d Cached threads: %lu Stack size: %ld\n",
575 count, thread_cache.size(),
576 (long) my_thread_stack_size);
577 #ifdef EXTRA_DEBUG
578 thr_print_locks(); // Write some debug info
579 print_cached_tables();
580 #endif
581 /* Print key cache status */
582 puts("\nKey caches:");
583 process_key_caches(print_key_cache_status, 0);
584 printf("\nhandler status:\n\
585 read_key: %10lu\n\
586 read_next: %10lu\n\
587 read_rnd %10lu\n\
588 read_first: %10lu\n\
589 write: %10lu\n\
590 delete %10lu\n\
591 update: %10lu\n",
592 tmp.ha_read_key_count,
593 tmp.ha_read_next_count,
594 tmp.ha_read_rnd_count,
595 tmp.ha_read_first_count,
596 tmp.ha_write_count,
597 tmp.ha_delete_count,
598 tmp.ha_update_count);
599 printf("\nTable status:\n\
600 Opened tables: %10lu\n\
601 Open tables: %10u\n\
602 Open files: %10u\n\
603 Open streams: %10lu\n",
604 tmp.opened_tables,
605 tc_records(),
606 my_file_opened,
607 my_stream_opened);
608
609 #ifndef DONT_USE_THR_ALARM
610 ALARM_INFO alarm_info;
611 thr_alarm_info(&alarm_info);
612 printf("\nAlarm status:\n\
613 Active alarms: %u\n\
614 Max used alarms: %u\n\
615 Next alarm time: %lu\n",
616 alarm_info.active_alarms,
617 alarm_info.max_used_alarms,
618 (ulong)alarm_info.next_alarm_time);
619 #endif
620 display_table_locks();
621 #if defined(HAVE_MALLINFO2)
622 struct mallinfo2 info = mallinfo2();
623 #elif defined(HAVE_MALLINFO)
624 struct mallinfo info= mallinfo();
625 #endif
626 #if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
627 char llbuff[10][22];
628 printf("\nMemory status:\n\
629 Non-mmapped space allocated from system: %s\n\
630 Number of free chunks: %lu\n\
631 Number of fastbin blocks: %lu\n\
632 Number of mmapped regions: %lu\n\
633 Space in mmapped regions: %s\n\
634 Maximum total allocated space: %s\n\
635 Space available in freed fastbin blocks: %s\n\
636 Total allocated space: %s\n\
637 Total free space: %s\n\
638 Top-most, releasable space: %s\n\
639 Estimated memory (with thread stack): %s\n\
640 Global memory allocated by server: %s\n\
641 Memory allocated by threads: %s\n",
642 llstr(info.arena, llbuff[0]),
643 (ulong) info.ordblks,
644 (ulong) info.smblks,
645 (ulong) info.hblks,
646 llstr(info.hblkhd, llbuff[1]),
647 llstr(info.usmblks, llbuff[2]),
648 llstr(info.fsmblks, llbuff[3]),
649 llstr(info.uordblks, llbuff[4]),
650 llstr(info.fordblks, llbuff[5]),
651 llstr(info.keepcost, llbuff[6]),
652 llstr((count + thread_cache.size()) * my_thread_stack_size +
653 info.hblkhd + info.arena, llbuff[7]),
654 llstr(tmp.global_memory_used, llbuff[8]),
655 llstr(tmp.local_memory_used, llbuff[9]));
656
657 #elif defined(HAVE_MALLOC_ZONE)
658 malloc_statistics_t info;
659 char llbuff[4][22];
660
661 malloc_zone_statistics(nullptr, &info);
662 printf("\nMemory status:\n\
663 Total allocated space: %s\n\
664 Total free space: %s\n\
665 Global memory allocated by server: %s\n\
666 Memory allocated by threads: %s\n",
667 llstr(info.size_allocated, llbuff[0]),
668 llstr((info.size_allocated - info.size_in_use), llbuff[1]),
669 llstr(tmp.global_memory_used, llbuff[2]),
670 llstr(tmp.local_memory_used, llbuff[3]));
671 #endif
672
673 #ifdef HAVE_EVENT_SCHEDULER
674 Events::dump_internal_status();
675 #endif
676 puts("");
677 fflush(stdout);
678 }
679
print_keyuse_array_for_trace(THD * thd,DYNAMIC_ARRAY * keyuse_array)680 void print_keyuse_array_for_trace(THD *thd, DYNAMIC_ARRAY *keyuse_array)
681 {
682 DBUG_ASSERT(thd->trace_started());
683
684 Json_writer_object wrapper(thd);
685 Json_writer_array trace_key_uses(thd, "ref_optimizer_key_uses");
686
687 for (uint i=0; i < keyuse_array->elements; i++)
688 {
689 KEYUSE *keyuse= (KEYUSE*)dynamic_array_ptr(keyuse_array, i);
690 Json_writer_object keyuse_elem(thd);
691 keyuse_elem.add_table_name(keyuse->table->reginfo.join_tab);
692 keyuse_elem.add("field", (keyuse->keypart == FT_KEYPART) ? "<fulltext>":
693 (keyuse->is_for_hash_join() ?
694 keyuse->table->field[keyuse->keypart]
695 ->field_name.str :
696 keyuse->table->key_info[keyuse->key]
697 .key_part[keyuse->keypart]
698 .field->field_name.str));
699 keyuse_elem.add("equals",keyuse->val);
700 keyuse_elem.add("null_rejecting",keyuse->null_rejecting);
701 }
702 }
703