1
/* Copyright (C) 2000-2006 MySQL 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; version 2 of the License.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
/* Write some debug info */
20
#include "mysql_priv.h"
21
#include "sql_select.h"
23
#include <thr_alarm.h>
24
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
26
#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H)
27
#include <sys/malloc.h>
30
#ifdef HAVE_EVENT_SCHEDULER
34
static const char *lock_descriptions[] =
36
/* TL_UNLOCK */ "No lock",
37
/* TL_READ_DEFAULT */ NULL,
38
/* TL_READ */ "Low priority read lock",
39
/* TL_READ_WITH_SHARED_LOCKS */ "Shared read lock",
40
/* TL_READ_HIGH_PRIORITY */ "High priority read lock",
41
/* TL_READ_NO_INSERT */ "Read lock without concurrent inserts",
42
/* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers",
43
/* TL_WRITE_ALLOW_READ */ "Write lock, but allow reading",
44
/* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock",
45
/* TL_WRITE_DELAYED */ "Lock used by delayed insert",
46
/* TL_WRITE_DEFAULT */ NULL,
47
/* TL_WRITE_LOW_PRIORITY */ "Low priority write lock",
48
/* TL_WRITE */ "High priority write lock",
49
/* TL_WRITE_ONLY */ "Highest priority write lock"
56
print_where(COND *cond,const char *info, enum_query_type query_type)
61
String str(buff,(uint32) sizeof(buff), system_charset_info);
63
cond->print(&str, query_type);
66
(void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
67
(void) fputs(str.ptr(),DBUG_FILE);
68
(void) fputc('\n',DBUG_FILE);
72
/* This is for debugging purposes */
75
void print_cached_tables(void)
77
uint idx,count,unused;
78
TABLE *start_link,*lnk;
80
compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions));
82
/* purecov: begin tested */
83
VOID(pthread_mutex_lock(&LOCK_open));
84
puts("DB Table Version Thread Open Lock");
86
for (idx=unused=0 ; idx < open_cache.records ; idx++)
88
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
89
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
90
entry->s->db.str, entry->s->table_name.str, entry->s->version,
91
entry->in_use ? entry->in_use->thread_id : 0L,
92
entry->db_stat ? 1 : 0,
93
entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
98
if ((start_link=lnk=unused_tables))
102
if (lnk != lnk->next->prev || lnk != lnk->prev->next)
104
printf("unused_links isn't linked properly\n");
107
} while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
108
if (lnk != start_link)
110
printf("Unused_links aren't connected\n");
114
printf("Unused_links (%d) doesn't match open_cache: %d\n", count,unused);
115
printf("\nCurrent refresh version: %ld\n",refresh_version);
116
if (hash_check(&open_cache))
117
printf("Error: File hash table is corrupted\n");
119
VOID(pthread_mutex_unlock(&LOCK_open));
125
void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
127
char buff[256],buff2[256];
128
String str(buff,sizeof(buff),system_charset_info);
129
String out(buff2,sizeof(buff2),system_charset_info);
131
DBUG_ENTER("TEST_filesort");
134
for (sep=""; s_length-- ; sortorder++, sep=" ")
137
if (sortorder->reverse)
139
if (sortorder->field)
141
if (sortorder->field->table_name)
143
out.append(*sortorder->field->table_name);
146
out.append(sortorder->field->field_name ? sortorder->field->field_name:
152
sortorder->item->print(&str, QT_ORDINARY);
156
out.append('\0'); // Purify doesn't like c_ptr()
158
VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
159
fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
166
TEST_join(JOIN *join)
169
DBUG_ENTER("TEST_join");
172
Assemble results of all the calls to full_name() first,
173
in order not to garble the tabular output below.
175
String ref_key_parts[MAX_TABLES];
176
for (i= 0; i < join->tables; i++)
178
JOIN_TAB *tab= join->join_tab + i;
179
for (ref= 0; ref < tab->ref.key_parts; ref++)
181
ref_key_parts[i].append(tab->ref.items[ref]->full_name());
182
ref_key_parts[i].append(" ");
187
VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
188
for (i=0 ; i < join->tables ; i++)
190
JOIN_TAB *tab=join->join_tab+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",
195
join_type_str[tab->type],
196
tab->keys.print(key_map_buff),
199
tab->ref.key_length);
202
char buf[MAX_KEY/8+1];
203
if (tab->use_quick == 2)
205
" quick select checked for each record (keys: %s)\n",
206
tab->select->quick_keys.print(buf));
207
else if (tab->select->quick)
209
fprintf(DBUG_FILE, " quick select used:\n");
210
tab->select->quick->dbug_dump(18, FALSE);
213
VOID(fputs(" select used\n",DBUG_FILE));
215
if (tab->ref.key_parts)
218
" refs: %s\n", ref_key_parts[i].ptr());
227
Print the current state during query optimization.
231
join pointer to the structure providing all context info for
233
read_time the cost of the best partial plan
234
record_count estimate for the number of records returned by the best
236
idx length of the partial QEP in 'join->positions';
237
also an index in the array 'join->best_ref';
238
info comment string to appear above the printout
241
This function prints to the log file DBUG_FILE the members of 'join' that
242
are used during query optimization (join->positions, join->best_positions,
243
and join->best_ref) and few other related variables (read_time,
245
Useful to trace query optimizer functions.
252
print_plan(JOIN* join, uint idx, double record_count, double read_time,
253
double current_read_time, const char *info)
257
JOIN_TAB *join_table;
258
JOIN_TAB **plan_nodes;
265
if (join->best_read == DBL_MAX)
268
"%s; idx: %u best: DBL_MAX atime: %g itime: %g count: %g\n",
269
info, idx, current_read_time, read_time, record_count);
274
"%s; idx :%u best: %g accumulated: %g increment: %g count: %g\n",
275
info, idx, join->best_read, current_read_time, read_time,
279
/* Print the tables in JOIN->positions */
280
fputs(" POSITIONS: ", DBUG_FILE);
281
for (i= 0; i < idx ; i++)
283
pos = join->positions[i];
284
table= pos.table->table;
286
fputs(table->s->table_name.str, DBUG_FILE);
287
fputc(' ', DBUG_FILE);
289
fputc('\n', DBUG_FILE);
292
Print the tables in JOIN->best_positions only if at least one complete plan
293
has been found. An indicator for this is the value of 'join->best_read'.
295
if (join->best_read < DBL_MAX)
297
fputs("BEST_POSITIONS: ", DBUG_FILE);
298
for (i= 0; i < idx ; i++)
300
pos= join->best_positions[i];
301
table= pos.table->table;
303
fputs(table->s->table_name.str, DBUG_FILE);
304
fputc(' ', DBUG_FILE);
307
fputc('\n', DBUG_FILE);
309
/* Print the tables in JOIN->best_ref */
310
fputs(" BEST_REF: ", DBUG_FILE);
311
for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++)
313
join_table= (*plan_nodes);
314
fputs(join_table->table->s->table_name.str, DBUG_FILE);
315
fprintf(DBUG_FILE, "(%lu,%lu,%lu)",
316
(ulong) join_table->found_records,
317
(ulong) join_table->records,
318
(ulong) join_table->read_time);
319
fputc(' ', DBUG_FILE);
321
fputc('\n', DBUG_FILE);
328
typedef struct st_debug_lock
331
char table_name[FN_REFLEN];
333
const char *lock_text;
334
enum thr_lock_type type;
337
static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b)
339
if (a->thread_id > b->thread_id)
341
if (a->thread_id < b->thread_id)
343
if (a->waiting == b->waiting)
351
static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
352
bool wait, const char *text)
356
TABLE *table=(TABLE *)data->debug_print_param;
357
if (table && table->s->tmp_table == NO_TMP_TABLE)
359
TABLE_LOCK_INFO table_lock_info;
360
table_lock_info.thread_id= table->in_use->thread_id;
361
memcpy(table_lock_info.table_name, table->s->table_cache_key.str,
362
table->s->table_cache_key.length);
363
table_lock_info.table_name[strlen(table_lock_info.table_name)]='.';
364
table_lock_info.waiting=wait;
365
table_lock_info.lock_text=text;
366
// lock_type is also obtainable from THR_LOCK_DATA
367
table_lock_info.type=table->reginfo.lock_type;
368
VOID(push_dynamic(ar,(uchar*) &table_lock_info));
375
Regarding MERGE tables:
377
For now, the best option is to use the common TABLE *pointer for all
378
cases; The drawback is that for MERGE tables we will see many locks
379
for the merge tables even if some of them are for individual tables.
381
The way to solve this is to add to 'THR_LOCK' structure a pointer to
382
the filename and use this when printing the data.
383
(We can for now ignore this and just print the same name for all merge
384
table parts; Please add the above as a comment to the display_lock
385
function so that we can easily add this if we ever need this.
388
static void display_table_locks(void)
391
DYNAMIC_ARRAY saved_table_locks;
393
VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50));
394
VOID(pthread_mutex_lock(&THR_LOCK_lock));
395
for (list= thr_lock_thread_list; list; list= list_rest(list))
397
THR_LOCK *lock=(THR_LOCK*) list->data;
399
VOID(pthread_mutex_lock(&lock->mutex));
400
push_locks_into_array(&saved_table_locks, lock->write.data, FALSE,
402
push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE,
404
push_locks_into_array(&saved_table_locks, lock->read.data, FALSE,
406
push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE,
408
VOID(pthread_mutex_unlock(&lock->mutex));
410
VOID(pthread_mutex_unlock(&THR_LOCK_lock));
411
if (!saved_table_locks.elements) goto end;
413
qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
414
freeze_size(&saved_table_locks);
416
puts("\nThread database.table_name Locked/Waiting Lock_type\n");
419
for (i=0 ; i < saved_table_locks.elements ; i++)
421
TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*);
422
printf("%-8ld%-28.28s%-22s%s\n",
423
dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]);
427
delete_dynamic(&saved_table_locks);
431
static int print_key_cache_status(const char *name, KEY_CACHE *key_cache)
438
if (!key_cache->key_cache_inited)
440
printf("%s: Not in use\n", name);
445
Buffer_size: %10lu\n\
447
Division_limit: %10lu\n\
449
blocks used: %10lu\n\
450
not flushed: %10lu\n\
456
(ulong) key_cache->param_buff_size, key_cache->param_block_size,
457
key_cache->param_division_limit, key_cache->param_age_threshold,
458
key_cache->blocks_used,key_cache->global_blocks_changed,
459
llstr(key_cache->global_cache_w_requests,llbuff1),
460
llstr(key_cache->global_cache_write,llbuff2),
461
llstr(key_cache->global_cache_r_requests,llbuff3),
462
llstr(key_cache->global_cache_read,llbuff4));
468
void mysql_print_status()
470
char current_dir[FN_REFLEN];
473
calc_sum_of_all_status(&tmp);
474
printf("\nStatus information:\n\n");
475
VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0)));
476
printf("Current dir: %s\n", current_dir);
477
printf("Running threads: %d Stack size: %ld\n", thread_count,
478
(long) my_thread_stack_size);
479
thr_print_locks(); // Write some debug info
481
print_cached_tables();
483
/* Print key cache status */
484
puts("\nKey caches:");
485
process_key_caches(print_key_cache_status);
486
pthread_mutex_lock(&LOCK_status);
487
printf("\nhandler status:\n\
495
tmp.ha_read_key_count,
496
tmp.ha_read_next_count,
497
tmp.ha_read_rnd_count,
498
tmp.ha_read_first_count,
501
tmp.ha_update_count);
502
pthread_mutex_unlock(&LOCK_status);
503
printf("\nTable status:\n\
504
Opened tables: %10lu\n\
505
Open tables: %10lu\n\
507
Open streams: %10lu\n",
509
(ulong) cached_open_tables(),
510
(ulong) my_file_opened,
511
(ulong) my_stream_opened);
513
ALARM_INFO alarm_info;
514
#ifndef DONT_USE_THR_ALARM
515
thr_alarm_info(&alarm_info);
516
printf("\nAlarm status:\n\
518
Max used alarms: %u\n\
519
Next alarm time: %lu\n",
520
alarm_info.active_alarms,
521
alarm_info.max_used_alarms,
522
alarm_info.next_alarm_time);
524
display_table_locks();
527
fprintf(stdout,"\nBegin safemalloc memory dump:\n"); // tag needed for test suite
528
TERMINATE(stdout, 1); // Write malloc information
529
fprintf(stdout,"\nEnd safemalloc memory dump.\n");
532
struct mallinfo info= mallinfo();
533
printf("\nMemory status:\n\
534
Non-mmapped space allocated from system: %d\n\
535
Number of free chunks: %d\n\
536
Number of fastbin blocks: %d\n\
537
Number of mmapped regions: %d\n\
538
Space in mmapped regions: %d\n\
539
Maximum total allocated space: %d\n\
540
Space available in freed fastbin blocks: %d\n\
541
Total allocated space: %d\n\
542
Total free space: %d\n\
543
Top-most, releasable space: %d\n\
544
Estimated memory (with thread stack): %ld\n",
555
(long) (thread_count * my_thread_stack_size + info.hblkhd + info.arena));
558
#ifdef HAVE_EVENT_SCHEDULER
559
Events::dump_internal_status();