1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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; either version 2 of the License, or
6
(at your option) any later version.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
/* Write some debug info */
21
#include "mysql_priv.h"
22
#include "sql_select.h"
24
#include <thr_alarm.h>
25
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
27
#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H)
28
#include <sys/malloc.h>
31
static const char *lock_descriptions[] =
34
"Low priority read lock",
36
"High priority read lock",
37
"Read lock without concurrent inserts",
38
"Write lock that allows other writers",
39
"Write lock, but allow reading",
40
"Concurrent insert lock",
41
"Lock Used by delayed insert",
42
"Low priority write lock",
43
"High priority write lock",
44
"Highest priority write lock"
51
print_where(COND *cond,const char *info)
56
String str(buff,(uint32) sizeof(buff), system_charset_info);
61
(void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
62
(void) fputs(str.ptr(),DBUG_FILE);
63
(void) fputc('\n',DBUG_FILE);
67
/* This is for debugging purposes */
70
void print_cached_tables(void)
72
uint idx,count,unused;
73
TABLE *start_link,*lnk;
75
VOID(pthread_mutex_lock(&LOCK_open));
76
puts("DB Table Version Thread L.thread Open Lock");
78
for (idx=unused=0 ; idx < open_cache.records ; idx++)
80
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
81
printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n",
82
entry->s->db, entry->s->table_name, entry->s->version,
83
entry->in_use ? entry->in_use->thread_id : 0L,
84
entry->in_use ? entry->in_use->dbug_thread_id : 0L,
85
entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
90
if ((start_link=lnk=unused_tables))
94
if (lnk != lnk->next->prev || lnk != lnk->prev->next)
96
printf("unused_links isn't linked properly\n");
99
} while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
100
if (lnk != start_link)
102
printf("Unused_links aren't connected\n");
106
printf("Unused_links (%d) doesn't match open_cache: %d\n", count,unused);
107
printf("\nCurrent refresh version: %ld\n",refresh_version);
108
if (hash_check(&open_cache))
109
printf("Error: File hash table is corrupted\n");
111
VOID(pthread_mutex_unlock(&LOCK_open));
116
void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
118
char buff[256],buff2[256];
119
String str(buff,sizeof(buff),system_charset_info);
120
String out(buff2,sizeof(buff2),system_charset_info);
122
DBUG_ENTER("TEST_filesort");
125
for (sep=""; s_length-- ; sortorder++, sep=" ")
128
if (sortorder->reverse)
130
if (sortorder->field)
132
if (sortorder->field->table_name)
134
out.append(*sortorder->field->table_name);
137
out.append(sortorder->field->field_name ? sortorder->field->field_name:
143
sortorder->item->print(&str);
147
out.append('\0'); // Purify doesn't like c_ptr()
149
VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
150
fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
157
TEST_join(JOIN *join)
160
DBUG_ENTER("TEST_join");
163
VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
164
for (i=0 ; i < join->tables ; i++)
166
JOIN_TAB *tab=join->join_tab+i;
167
TABLE *form=tab->table;
168
char key_map_buff[128];
169
fprintf(DBUG_FILE,"%-16.16s type: %-7s q_keys: %s refs: %d key: %d len: %d\n",
171
join_type_str[tab->type],
172
tab->keys.print(key_map_buff),
175
tab->ref.key_length);
178
char buf[MAX_KEY/8+1];
179
if (tab->use_quick == 2)
181
" quick select checked for each record (keys: %s)\n",
182
tab->select->quick_keys.print(buf));
183
else if (tab->select->quick)
185
fprintf(DBUG_FILE, " quick select used:\n");
186
tab->select->quick->dbug_dump(18, FALSE);
189
VOID(fputs(" select used\n",DBUG_FILE));
191
if (tab->ref.key_parts)
193
VOID(fputs(" refs: ",DBUG_FILE));
194
for (ref=0 ; ref < tab->ref.key_parts ; ref++)
196
Item *item=tab->ref.items[ref];
197
fprintf(DBUG_FILE,"%s ", item->full_name());
199
VOID(fputc('\n',DBUG_FILE));
208
Print the current state during query optimization.
212
join pointer to the structure providing all context info for
214
read_time the cost of the best partial plan
215
record_count estimate for the number of records returned by the best
217
idx length of the partial QEP in 'join->positions';
218
also an index in the array 'join->best_ref';
219
info comment string to appear above the printout
222
This function prints to the log file DBUG_FILE the members of 'join' that
223
are used during query optimization (join->positions, join->best_positions,
224
and join->best_ref) and few other related variables (read_time,
226
Useful to trace query optimizer functions.
233
print_plan(JOIN* join, uint idx, double record_count, double read_time,
234
double current_read_time, const char *info)
238
JOIN_TAB *join_table;
239
JOIN_TAB **plan_nodes;
246
if (join->best_read == DBL_MAX)
249
"%s; idx:%u, best: DBL_MAX, atime: %g, itime: %g, count: %g\n",
250
info, idx, current_read_time, read_time, record_count);
255
"%s; idx:%u, best: %g, accumulated: %g, increment: %g, count: %g\n",
256
info, idx, join->best_read, current_read_time, read_time, record_count);
259
/* Print the tables in JOIN->positions */
260
fputs(" POSITIONS: ", DBUG_FILE);
261
for (i= 0; i < idx ; i++)
263
pos = join->positions[i];
264
table= pos.table->table;
266
fputs(table->s->table_name, DBUG_FILE);
267
fputc(' ', DBUG_FILE);
269
fputc('\n', DBUG_FILE);
272
Print the tables in JOIN->best_positions only if at least one complete plan
273
has been found. An indicator for this is the value of 'join->best_read'.
275
if (join->best_read < DBL_MAX)
277
fputs("BEST_POSITIONS: ", DBUG_FILE);
278
for (i= 0; i < idx ; i++)
280
pos= join->best_positions[i];
281
table= pos.table->table;
283
fputs(table->s->table_name, DBUG_FILE);
284
fputc(' ', DBUG_FILE);
287
fputc('\n', DBUG_FILE);
289
/* Print the tables in JOIN->best_ref */
290
fputs(" BEST_REF: ", DBUG_FILE);
291
for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++)
293
join_table= (*plan_nodes);
294
fputs(join_table->table->s->table_name, DBUG_FILE);
295
fprintf(DBUG_FILE, "(%lu,%lu,%lu)",
296
(ulong) join_table->found_records,
297
(ulong) join_table->records,
298
(ulong) join_table->read_time);
299
fputc(' ', DBUG_FILE);
301
fputc('\n', DBUG_FILE);
308
typedef struct st_debug_lock
311
char table_name[FN_REFLEN];
313
const char *lock_text;
314
enum thr_lock_type type;
317
static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b)
319
if (a->thread_id > b->thread_id)
321
if (a->thread_id < b->thread_id)
323
if (a->waiting == b->waiting)
331
static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
332
bool wait, const char *text)
336
TABLE *table=(TABLE *)data->debug_print_param;
337
if (table && table->s->tmp_table == NO_TMP_TABLE)
339
TABLE_LOCK_INFO table_lock_info;
340
table_lock_info.thread_id= table->in_use->thread_id;
341
memcpy(table_lock_info.table_name, table->s->table_cache_key,
342
table->s->key_length);
343
table_lock_info.table_name[strlen(table_lock_info.table_name)]='.';
344
table_lock_info.waiting=wait;
345
table_lock_info.lock_text=text;
346
// lock_type is also obtainable from THR_LOCK_DATA
347
table_lock_info.type=table->reginfo.lock_type;
348
VOID(push_dynamic(ar,(gptr) &table_lock_info));
355
Regarding MERGE tables:
357
For now, the best option is to use the common TABLE *pointer for all
358
cases; The drawback is that for MERGE tables we will see many locks
359
for the merge tables even if some of them are for individual tables.
361
The way to solve this is to add to 'THR_LOCK' structure a pointer to
362
the filename and use this when printing the data.
363
(We can for now ignore this and just print the same name for all merge
364
table parts; Please add the above as a comment to the display_lock
365
function so that we can easily add this if we ever need this.
368
static void display_table_locks(void)
371
DYNAMIC_ARRAY saved_table_locks;
373
VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50));
374
VOID(pthread_mutex_lock(&THR_LOCK_lock));
375
for (list= thr_lock_thread_list; list; list= list_rest(list))
377
THR_LOCK *lock=(THR_LOCK*) list->data;
379
VOID(pthread_mutex_lock(&lock->mutex));
380
push_locks_into_array(&saved_table_locks, lock->write.data, FALSE,
382
push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE,
384
push_locks_into_array(&saved_table_locks, lock->read.data, FALSE,
386
push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE,
388
VOID(pthread_mutex_unlock(&lock->mutex));
390
VOID(pthread_mutex_unlock(&THR_LOCK_lock));
391
if (!saved_table_locks.elements) goto end;
393
qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
394
freeze_size(&saved_table_locks);
396
puts("\nThread database.table_name Locked/Waiting Lock_type\n");
399
for (i=0 ; i < saved_table_locks.elements ; i++)
401
TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*);
402
printf("%-8ld%-28.28s%-22s%s\n",
403
dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]);
407
delete_dynamic(&saved_table_locks);
411
static int print_key_cache_status(const char *name, KEY_CACHE *key_cache)
418
if (!key_cache->key_cache_inited)
420
printf("%s: Not in use\n", name);
425
Buffer_size: %10lu\n\
427
Division_limit: %10lu\n\
429
blocks used: %10lu\n\
430
not flushed: %10lu\n\
436
(ulong) key_cache->param_buff_size, key_cache->param_block_size,
437
key_cache->param_division_limit, key_cache->param_age_threshold,
438
key_cache->blocks_used,key_cache->global_blocks_changed,
439
llstr(key_cache->global_cache_w_requests,llbuff1),
440
llstr(key_cache->global_cache_write,llbuff2),
441
llstr(key_cache->global_cache_r_requests,llbuff3),
442
llstr(key_cache->global_cache_read,llbuff4));
448
void mysql_print_status()
450
char current_dir[FN_REFLEN];
453
calc_sum_of_all_status(&tmp);
454
printf("\nStatus information:\n\n");
455
VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0)));
456
printf("Current dir: %s\n", current_dir);
457
printf("Running threads: %d Stack size: %ld\n", thread_count,
458
(long) thread_stack);
459
thr_print_locks(); // Write some debug info
461
print_cached_tables();
463
/* Print key cache status */
464
puts("\nKey caches:");
465
process_key_caches(print_key_cache_status);
466
pthread_mutex_lock(&LOCK_status);
467
printf("\nhandler status:\n\
475
tmp.ha_read_key_count,
476
tmp.ha_read_next_count,
477
tmp.ha_read_rnd_count,
478
tmp.ha_read_first_count,
481
tmp.ha_update_count);
482
pthread_mutex_unlock(&LOCK_status);
483
printf("\nTable status:\n\
484
Opened tables: %10lu\n\
485
Open tables: %10lu\n\
487
Open streams: %10lu\n",
489
(ulong) cached_tables(),
490
(ulong) my_file_opened,
491
(ulong) my_stream_opened);
493
ALARM_INFO alarm_info;
494
#ifndef DONT_USE_THR_ALARM
495
thr_alarm_info(&alarm_info);
496
printf("\nAlarm status:\n\
498
Max used alarms: %u\n\
499
Next alarm time: %lu\n",
500
alarm_info.active_alarms,
501
alarm_info.max_used_alarms,
502
alarm_info.next_alarm_time);
504
display_table_locks();
507
TERMINATE(stdout); // Write malloc information
510
struct mallinfo info= mallinfo();
511
printf("\nMemory status:\n\
512
Non-mmapped space allocated from system: %d\n\
513
Number of free chunks: %d\n\
514
Number of fastbin blocks: %d\n\
515
Number of mmapped regions: %d\n\
516
Space in mmapped regions: %d\n\
517
Maximum total allocated space: %d\n\
518
Space available in freed fastbin blocks: %d\n\
519
Total allocated space: %d\n\
520
Total free space: %d\n\
521
Top-most, releasable space: %d\n\
522
Estimated memory (with thread stack): %ld\n",
533
(long) (thread_count * thread_stack + info.hblkhd + info.arena));