1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2006 MySQL AB
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
||
17 |
/* Write some debug info */
|
|
18 |
||
19 |
||
20 |
#include "mysql_priv.h" |
|
21 |
#include "sql_select.h" |
|
22 |
#include <hash.h> |
|
23 |
#include <thr_alarm.h> |
|
24 |
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
|
|
25 |
#include <malloc.h> |
|
26 |
#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H)
|
|
27 |
#include <sys/malloc.h> |
|
28 |
#endif
|
|
29 |
||
30 |
static const char *lock_descriptions[] = |
|
31 |
{
|
|
32 |
"No lock", |
|
33 |
"Low priority read lock", |
|
34 |
"Shared Read lock", |
|
35 |
"High priority read lock", |
|
36 |
"Read lock without concurrent inserts", |
|
37 |
"Write lock that allows other writers", |
|
38 |
"Write lock, but allow reading", |
|
39 |
"Concurrent insert lock", |
|
40 |
"Lock Used by delayed insert", |
|
41 |
"Low priority write lock", |
|
42 |
"High priority write lock", |
|
43 |
"Highest priority write lock"
|
|
44 |
};
|
|
45 |
||
46 |
||
47 |
#ifndef DBUG_OFF
|
|
48 |
||
49 |
void
|
|
50 |
print_where(COND *cond,const char *info, enum_query_type query_type) |
|
51 |
{
|
|
52 |
if (cond) |
|
53 |
{
|
|
54 |
char buff[256]; |
|
55 |
String str(buff,(uint32) sizeof(buff), system_charset_info); |
|
56 |
str.length(0); |
|
57 |
cond->print(&str, query_type); |
|
58 |
str.append('\0'); |
|
59 |
DBUG_LOCK_FILE; |
|
60 |
(void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info); |
|
61 |
(void) fputs(str.ptr(),DBUG_FILE); |
|
62 |
(void) fputc('\n',DBUG_FILE); |
|
63 |
DBUG_UNLOCK_FILE; |
|
64 |
}
|
|
65 |
}
|
|
66 |
/* This is for debugging purposes */
|
|
67 |
||
68 |
||
69 |
void print_cached_tables(void) |
|
70 |
{
|
|
71 |
uint idx,count,unused; |
|
72 |
TABLE *start_link,*lnk; |
|
73 |
||
74 |
/* purecov: begin tested */
|
|
75 |
VOID(pthread_mutex_lock(&LOCK_open)); |
|
76 |
puts("DB Table Version Thread Open Lock"); |
|
77 |
||
78 |
for (idx=unused=0 ; idx < open_cache.records ; idx++) |
|
79 |
{
|
|
80 |
TABLE *entry=(TABLE*) hash_element(&open_cache,idx); |
|
81 |
printf("%-14.14s %-32s%6ld%8ld%6d %s\n", |
|
82 |
entry->s->db.str, entry->s->table_name.str, entry->s->version, |
|
83 |
entry->in_use ? entry->in_use->thread_id : 0L, |
|
84 |
entry->db_stat ? 1 : 0, |
|
85 |
entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use"); |
|
86 |
if (!entry->in_use) |
|
87 |
unused++; |
|
88 |
}
|
|
89 |
count=0; |
|
90 |
if ((start_link=lnk=unused_tables)) |
|
91 |
{
|
|
92 |
do
|
|
93 |
{
|
|
94 |
if (lnk != lnk->next->prev || lnk != lnk->prev->next) |
|
95 |
{
|
|
96 |
printf("unused_links isn't linked properly\n"); |
|
97 |
return; |
|
98 |
}
|
|
99 |
} while (count++ < open_cache.records && (lnk=lnk->next) != start_link); |
|
100 |
if (lnk != start_link) |
|
101 |
{
|
|
102 |
printf("Unused_links aren't connected\n"); |
|
103 |
}
|
|
104 |
}
|
|
105 |
if (count != unused) |
|
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"); |
|
110 |
fflush(stdout); |
|
111 |
VOID(pthread_mutex_unlock(&LOCK_open)); |
|
112 |
/* purecov: end */
|
|
113 |
return; |
|
114 |
}
|
|
115 |
||
116 |
||
117 |
void TEST_filesort(SORT_FIELD *sortorder,uint s_length) |
|
118 |
{
|
|
119 |
char buff[256],buff2[256]; |
|
120 |
String str(buff,sizeof(buff),system_charset_info); |
|
121 |
String out(buff2,sizeof(buff2),system_charset_info); |
|
122 |
const char *sep; |
|
123 |
DBUG_ENTER("TEST_filesort"); |
|
124 |
||
125 |
out.length(0); |
|
126 |
for (sep=""; s_length-- ; sortorder++, sep=" ") |
|
127 |
{
|
|
128 |
out.append(sep); |
|
129 |
if (sortorder->reverse) |
|
130 |
out.append('-'); |
|
131 |
if (sortorder->field) |
|
132 |
{
|
|
133 |
if (sortorder->field->table_name) |
|
134 |
{
|
|
135 |
out.append(*sortorder->field->table_name); |
|
136 |
out.append('.'); |
|
137 |
}
|
|
138 |
out.append(sortorder->field->field_name ? sortorder->field->field_name: |
|
139 |
"tmp_table_column"); |
|
140 |
}
|
|
141 |
else
|
|
142 |
{
|
|
143 |
str.length(0); |
|
144 |
sortorder->item->print(&str, QT_ORDINARY); |
|
145 |
out.append(str); |
|
146 |
}
|
|
147 |
}
|
|
148 |
out.append('\0'); // Purify doesn't like c_ptr() |
|
149 |
DBUG_LOCK_FILE; |
|
150 |
VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE)); |
|
151 |
fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr()); |
|
152 |
DBUG_UNLOCK_FILE; |
|
153 |
DBUG_VOID_RETURN; |
|
154 |
}
|
|
155 |
||
156 |
||
157 |
void
|
|
158 |
TEST_join(JOIN *join) |
|
159 |
{
|
|
160 |
uint i,ref; |
|
161 |
DBUG_ENTER("TEST_join"); |
|
162 |
||
163 |
DBUG_LOCK_FILE; |
|
164 |
VOID(fputs("\nInfo about JOIN\n",DBUG_FILE)); |
|
165 |
for (i=0 ; i < join->tables ; i++) |
|
166 |
{
|
|
167 |
JOIN_TAB *tab=join->join_tab+i; |
|
168 |
TABLE *form=tab->table; |
|
169 |
char key_map_buff[128]; |
|
170 |
fprintf(DBUG_FILE,"%-16.16s type: %-7s q_keys: %s refs: %d key: %d len: %d\n", |
|
171 |
form->alias, |
|
172 |
join_type_str[tab->type], |
|
173 |
tab->keys.print(key_map_buff), |
|
174 |
tab->ref.key_parts, |
|
175 |
tab->ref.key, |
|
176 |
tab->ref.key_length); |
|
177 |
if (tab->select) |
|
178 |
{
|
|
179 |
char buf[MAX_KEY/8+1]; |
|
180 |
if (tab->use_quick == 2) |
|
181 |
fprintf(DBUG_FILE, |
|
182 |
" quick select checked for each record (keys: %s)\n", |
|
183 |
tab->select->quick_keys.print(buf)); |
|
184 |
else if (tab->select->quick) |
|
185 |
{
|
|
186 |
fprintf(DBUG_FILE, " quick select used:\n"); |
|
187 |
tab->select->quick->dbug_dump(18, FALSE); |
|
188 |
}
|
|
189 |
else
|
|
190 |
VOID(fputs(" select used\n",DBUG_FILE)); |
|
191 |
}
|
|
192 |
if (tab->ref.key_parts) |
|
193 |
{
|
|
194 |
VOID(fputs(" refs: ",DBUG_FILE)); |
|
195 |
for (ref=0 ; ref < tab->ref.key_parts ; ref++) |
|
196 |
{
|
|
197 |
Item *item=tab->ref.items[ref]; |
|
198 |
fprintf(DBUG_FILE,"%s ", item->full_name()); |
|
199 |
}
|
|
200 |
VOID(fputc('\n',DBUG_FILE)); |
|
201 |
}
|
|
202 |
}
|
|
203 |
DBUG_UNLOCK_FILE; |
|
204 |
DBUG_VOID_RETURN; |
|
205 |
}
|
|
206 |
||
207 |
#define FT_KEYPART (MAX_REF_PARTS+10)
|
|
208 |
||
209 |
void print_keyuse(KEYUSE *keyuse) |
|
210 |
{
|
|
211 |
char buff[256]; |
|
212 |
char buf2[64]; |
|
213 |
const char *fieldname; |
|
214 |
String str(buff,(uint32) sizeof(buff), system_charset_info); |
|
215 |
str.length(0); |
|
216 |
keyuse->val->print(&str, QT_ORDINARY); |
|
217 |
str.append('\0'); |
|
218 |
if (keyuse->keypart == FT_KEYPART) |
|
219 |
fieldname= "FT_KEYPART"; |
|
220 |
else
|
|
221 |
fieldname= keyuse->table->key_info[keyuse->key].key_part[keyuse->keypart].field->field_name; |
|
222 |
longlong2str(keyuse->used_tables, buf2, 16); |
|
223 |
DBUG_LOCK_FILE; |
|
224 |
fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize= %d used_tables=%s " |
|
225 |
"ref_table_rows= %lu keypart_map= %0lx\n", |
|
226 |
keyuse->table->alias, fieldname, str.ptr(), |
|
227 |
keyuse->optimize, buf2, (ulong)keyuse->ref_table_rows, |
|
228 |
keyuse->keypart_map); |
|
229 |
DBUG_UNLOCK_FILE; |
|
230 |
//key_part_map keypart_map; --?? there can be several?
|
|
231 |
}
|
|
232 |
||
233 |
||
234 |
void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array) |
|
235 |
{
|
|
236 |
DBUG_LOCK_FILE; |
|
237 |
fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements); |
|
238 |
DBUG_UNLOCK_FILE; |
|
239 |
for(uint i=0; i < keyuse_array->elements; i++) |
|
240 |
print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i)); |
|
241 |
}
|
|
242 |
||
243 |
||
244 |
/*
|
|
245 |
Print the current state during query optimization.
|
|
246 |
||
247 |
SYNOPSIS
|
|
248 |
print_plan()
|
|
249 |
join pointer to the structure providing all context info for
|
|
250 |
the query
|
|
251 |
read_time the cost of the best partial plan
|
|
252 |
record_count estimate for the number of records returned by the best
|
|
253 |
partial plan
|
|
254 |
idx length of the partial QEP in 'join->positions';
|
|
255 |
also an index in the array 'join->best_ref';
|
|
256 |
info comment string to appear above the printout
|
|
257 |
||
258 |
DESCRIPTION
|
|
259 |
This function prints to the log file DBUG_FILE the members of 'join' that
|
|
260 |
are used during query optimization (join->positions, join->best_positions,
|
|
261 |
and join->best_ref) and few other related variables (read_time,
|
|
262 |
record_count).
|
|
263 |
Useful to trace query optimizer functions.
|
|
264 |
||
265 |
RETURN
|
|
266 |
None
|
|
267 |
*/
|
|
268 |
||
269 |
void
|
|
270 |
print_plan(JOIN* join, uint idx, double record_count, double read_time, |
|
271 |
double current_read_time, const char *info) |
|
272 |
{
|
|
273 |
uint i; |
|
274 |
POSITION pos; |
|
275 |
JOIN_TAB *join_table; |
|
276 |
JOIN_TAB **plan_nodes; |
|
277 |
TABLE* table; |
|
278 |
||
279 |
if (info == 0) |
|
280 |
info= ""; |
|
281 |
||
282 |
DBUG_LOCK_FILE; |
|
283 |
if (join->best_read == DBL_MAX) |
|
284 |
{
|
|
285 |
fprintf(DBUG_FILE, |
|
286 |
"%s; idx: %u best: DBL_MAX atime: %g itime: %g count: %g\n", |
|
287 |
info, idx, current_read_time, read_time, record_count); |
|
288 |
}
|
|
289 |
else
|
|
290 |
{
|
|
291 |
fprintf(DBUG_FILE, |
|
292 |
"%s; idx :%u best: %g accumulated: %g increment: %g count: %g\n", |
|
293 |
info, idx, join->best_read, current_read_time, read_time, |
|
294 |
record_count); |
|
295 |
}
|
|
296 |
||
297 |
/* Print the tables in JOIN->positions */
|
|
298 |
fputs(" POSITIONS: ", DBUG_FILE); |
|
299 |
for (i= 0; i < idx ; i++) |
|
300 |
{
|
|
301 |
pos = join->positions[i]; |
|
302 |
table= pos.table->table; |
|
303 |
if (table) |
|
304 |
fputs(table->s->table_name.str, DBUG_FILE); |
|
305 |
fputc(' ', DBUG_FILE); |
|
306 |
}
|
|
307 |
fputc('\n', DBUG_FILE); |
|
308 |
||
309 |
/*
|
|
310 |
Print the tables in JOIN->best_positions only if at least one complete plan
|
|
311 |
has been found. An indicator for this is the value of 'join->best_read'.
|
|
312 |
*/
|
|
313 |
if (join->best_read < DBL_MAX) |
|
314 |
{
|
|
315 |
fputs("BEST_POSITIONS: ", DBUG_FILE); |
|
316 |
for (i= 0; i < idx ; i++) |
|
317 |
{
|
|
318 |
pos= join->best_positions[i]; |
|
319 |
table= pos.table->table; |
|
320 |
if (table) |
|
321 |
fputs(table->s->table_name.str, DBUG_FILE); |
|
322 |
fputc(' ', DBUG_FILE); |
|
323 |
}
|
|
324 |
}
|
|
325 |
fputc('\n', DBUG_FILE); |
|
326 |
||
327 |
/* Print the tables in JOIN->best_ref */
|
|
328 |
fputs(" BEST_REF: ", DBUG_FILE); |
|
329 |
for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++) |
|
330 |
{
|
|
331 |
join_table= (*plan_nodes); |
|
332 |
fputs(join_table->table->s->table_name.str, DBUG_FILE); |
|
333 |
fprintf(DBUG_FILE, "(%lu,%lu,%lu)", |
|
334 |
(ulong) join_table->found_records, |
|
335 |
(ulong) join_table->records, |
|
336 |
(ulong) join_table->read_time); |
|
337 |
fputc(' ', DBUG_FILE); |
|
338 |
}
|
|
339 |
fputc('\n', DBUG_FILE); |
|
340 |
||
341 |
DBUG_UNLOCK_FILE; |
|
342 |
}
|
|
343 |
||
344 |
#endif
|
|
345 |
||
346 |
typedef struct st_debug_lock |
|
347 |
{
|
|
348 |
ulong thread_id; |
|
349 |
char table_name[FN_REFLEN]; |
|
350 |
bool waiting; |
|
351 |
const char *lock_text; |
|
352 |
enum thr_lock_type type; |
|
353 |
} TABLE_LOCK_INFO; |
|
354 |
||
355 |
static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b) |
|
356 |
{
|
|
357 |
if (a->thread_id > b->thread_id) |
|
358 |
return 1; |
|
359 |
if (a->thread_id < b->thread_id) |
|
360 |
return -1; |
|
361 |
if (a->waiting == b->waiting) |
|
362 |
return 0; |
|
363 |
else if (a->waiting) |
|
364 |
return -1; |
|
365 |
return 1; |
|
366 |
}
|
|
367 |
||
368 |
||
369 |
static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, |
|
370 |
bool wait, const char *text) |
|
371 |
{
|
|
372 |
if (data) |
|
373 |
{
|
|
374 |
TABLE *table=(TABLE *)data->debug_print_param; |
|
375 |
if (table && table->s->tmp_table == NO_TMP_TABLE) |
|
376 |
{
|
|
377 |
TABLE_LOCK_INFO table_lock_info; |
|
378 |
table_lock_info.thread_id= table->in_use->thread_id; |
|
379 |
memcpy(table_lock_info.table_name, table->s->table_cache_key.str, |
|
380 |
table->s->table_cache_key.length); |
|
381 |
table_lock_info.table_name[strlen(table_lock_info.table_name)]='.'; |
|
382 |
table_lock_info.waiting=wait; |
|
383 |
table_lock_info.lock_text=text; |
|
384 |
// lock_type is also obtainable from THR_LOCK_DATA
|
|
385 |
table_lock_info.type=table->reginfo.lock_type; |
|
386 |
VOID(push_dynamic(ar,(uchar*) &table_lock_info)); |
|
387 |
}
|
|
388 |
}
|
|
389 |
}
|
|
390 |
||
391 |
||
392 |
/*
|
|
393 |
Regarding MERGE tables:
|
|
394 |
||
395 |
For now, the best option is to use the common TABLE *pointer for all
|
|
396 |
cases; The drawback is that for MERGE tables we will see many locks
|
|
397 |
for the merge tables even if some of them are for individual tables.
|
|
398 |
||
399 |
The way to solve this is to add to 'THR_LOCK' structure a pointer to
|
|
400 |
the filename and use this when printing the data.
|
|
401 |
(We can for now ignore this and just print the same name for all merge
|
|
402 |
table parts; Please add the above as a comment to the display_lock
|
|
403 |
function so that we can easily add this if we ever need this.
|
|
404 |
*/
|
|
405 |
||
406 |
static void display_table_locks(void) |
|
407 |
{
|
|
408 |
LIST *list; |
|
409 |
DYNAMIC_ARRAY saved_table_locks; |
|
410 |
||
411 |
VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50)); |
|
412 |
VOID(pthread_mutex_lock(&THR_LOCK_lock)); |
|
413 |
for (list= thr_lock_thread_list; list; list= list_rest(list)) |
|
414 |
{
|
|
415 |
THR_LOCK *lock=(THR_LOCK*) list->data; |
|
416 |
||
417 |
VOID(pthread_mutex_lock(&lock->mutex)); |
|
418 |
push_locks_into_array(&saved_table_locks, lock->write.data, FALSE, |
|
419 |
"Locked - write"); |
|
420 |
push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE, |
|
421 |
"Waiting - write"); |
|
422 |
push_locks_into_array(&saved_table_locks, lock->read.data, FALSE, |
|
423 |
"Locked - read"); |
|
424 |
push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE, |
|
425 |
"Waiting - read"); |
|
426 |
VOID(pthread_mutex_unlock(&lock->mutex)); |
|
427 |
}
|
|
428 |
VOID(pthread_mutex_unlock(&THR_LOCK_lock)); |
|
429 |
if (!saved_table_locks.elements) goto end; |
|
430 |
||
431 |
qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); |
|
432 |
freeze_size(&saved_table_locks); |
|
433 |
||
434 |
puts("\nThread database.table_name Locked/Waiting Lock_type\n"); |
|
435 |
||
436 |
unsigned int i; |
|
437 |
for (i=0 ; i < saved_table_locks.elements ; i++) |
|
438 |
{
|
|
439 |
TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*); |
|
440 |
printf("%-8ld%-28.28s%-22s%s\n", |
|
441 |
dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]); |
|
442 |
}
|
|
443 |
puts("\n\n"); |
|
444 |
end: |
|
445 |
delete_dynamic(&saved_table_locks); |
|
446 |
}
|
|
447 |
||
448 |
||
449 |
static int print_key_cache_status(const char *name, KEY_CACHE *key_cache) |
|
450 |
{
|
|
451 |
char llbuff1[22]; |
|
452 |
char llbuff2[22]; |
|
453 |
char llbuff3[22]; |
|
454 |
char llbuff4[22]; |
|
455 |
||
456 |
if (!key_cache->key_cache_inited) |
|
457 |
{
|
|
458 |
printf("%s: Not in use\n", name); |
|
459 |
}
|
|
460 |
else
|
|
461 |
{
|
|
462 |
printf("%s\n\ |
|
463 |
Buffer_size: %10lu\n\ |
|
464 |
Block_size: %10lu\n\ |
|
465 |
Division_limit: %10lu\n\ |
|
466 |
Age_limit: %10lu\n\ |
|
467 |
blocks used: %10lu\n\ |
|
468 |
not flushed: %10lu\n\ |
|
469 |
w_requests: %10s\n\ |
|
470 |
writes: %10s\n\ |
|
471 |
r_requests: %10s\n\ |
|
472 |
reads: %10s\n\n", |
|
473 |
name, |
|
474 |
(ulong) key_cache->param_buff_size, key_cache->param_block_size, |
|
475 |
key_cache->param_division_limit, key_cache->param_age_threshold, |
|
476 |
key_cache->blocks_used,key_cache->global_blocks_changed, |
|
477 |
llstr(key_cache->global_cache_w_requests,llbuff1), |
|
478 |
llstr(key_cache->global_cache_write,llbuff2), |
|
479 |
llstr(key_cache->global_cache_r_requests,llbuff3), |
|
480 |
llstr(key_cache->global_cache_read,llbuff4)); |
|
481 |
}
|
|
482 |
return 0; |
|
483 |
}
|
|
484 |
||
485 |
||
486 |
void mysql_print_status() |
|
487 |
{
|
|
488 |
char current_dir[FN_REFLEN]; |
|
489 |
STATUS_VAR tmp; |
|
490 |
||
491 |
calc_sum_of_all_status(&tmp); |
|
492 |
printf("\nStatus information:\n\n"); |
|
493 |
VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0))); |
|
494 |
printf("Current dir: %s\n", current_dir); |
|
495 |
printf("Running threads: %d Stack size: %ld\n", thread_count, |
|
496 |
(long) my_thread_stack_size); |
|
497 |
thr_print_locks(); // Write some debug info |
|
498 |
#ifndef DBUG_OFF
|
|
499 |
print_cached_tables(); |
|
500 |
#endif
|
|
501 |
/* Print key cache status */
|
|
502 |
puts("\nKey caches:"); |
|
503 |
process_key_caches(print_key_cache_status); |
|
504 |
pthread_mutex_lock(&LOCK_status); |
|
505 |
printf("\nhandler status:\n\ |
|
506 |
read_key: %10lu\n\ |
|
507 |
read_next: %10lu\n\ |
|
508 |
read_rnd %10lu\n\ |
|
509 |
read_first: %10lu\n\ |
|
510 |
write: %10lu\n\ |
|
511 |
delete %10lu\n\ |
|
512 |
update: %10lu\n", |
|
513 |
tmp.ha_read_key_count, |
|
514 |
tmp.ha_read_next_count, |
|
515 |
tmp.ha_read_rnd_count, |
|
516 |
tmp.ha_read_first_count, |
|
517 |
tmp.ha_write_count, |
|
518 |
tmp.ha_delete_count, |
|
519 |
tmp.ha_update_count); |
|
520 |
pthread_mutex_unlock(&LOCK_status); |
|
521 |
printf("\nTable status:\n\ |
|
522 |
Opened tables: %10lu\n\ |
|
523 |
Open tables: %10lu\n\ |
|
524 |
Open files: %10lu\n\ |
|
525 |
Open streams: %10lu\n", |
|
526 |
tmp.opened_tables, |
|
527 |
(ulong) cached_open_tables(), |
|
528 |
(ulong) my_file_opened, |
|
529 |
(ulong) my_stream_opened); |
|
530 |
||
531 |
ALARM_INFO alarm_info; |
|
532 |
#ifndef DONT_USE_THR_ALARM
|
|
533 |
thr_alarm_info(&alarm_info); |
|
534 |
printf("\nAlarm status:\n\ |
|
535 |
Active alarms: %u\n\ |
|
536 |
Max used alarms: %u\n\ |
|
537 |
Next alarm time: %lu\n", |
|
538 |
alarm_info.active_alarms, |
|
539 |
alarm_info.max_used_alarms, |
|
540 |
alarm_info.next_alarm_time); |
|
541 |
#endif
|
|
542 |
display_table_locks(); |
|
543 |
fflush(stdout); |
|
544 |
my_checkmalloc(); |
|
545 |
fprintf(stdout,"\nBegin safemalloc memory dump:\n"); // tag needed for test suite |
|
546 |
TERMINATE(stdout, 1); // Write malloc information |
|
547 |
fprintf(stdout,"\nEnd safemalloc memory dump.\n"); |
|
548 |
||
549 |
#ifdef HAVE_MALLINFO
|
|
550 |
struct mallinfo info= mallinfo(); |
|
551 |
printf("\nMemory status:\n\ |
|
552 |
Non-mmapped space allocated from system: %d\n\ |
|
553 |
Number of free chunks: %d\n\ |
|
554 |
Number of fastbin blocks: %d\n\ |
|
555 |
Number of mmapped regions: %d\n\ |
|
556 |
Space in mmapped regions: %d\n\ |
|
557 |
Maximum total allocated space: %d\n\ |
|
558 |
Space available in freed fastbin blocks: %d\n\ |
|
559 |
Total allocated space: %d\n\ |
|
560 |
Total free space: %d\n\ |
|
561 |
Top-most, releasable space: %d\n\ |
|
562 |
Estimated memory (with thread stack): %ld\n", |
|
563 |
(int) info.arena , |
|
564 |
(int) info.ordblks, |
|
565 |
(int) info.smblks, |
|
566 |
(int) info.hblks, |
|
567 |
(int) info.hblkhd, |
|
568 |
(int) info.usmblks, |
|
569 |
(int) info.fsmblks, |
|
570 |
(int) info.uordblks, |
|
571 |
(int) info.fordblks, |
|
572 |
(int) info.keepcost, |
|
573 |
(long) (thread_count * my_thread_stack_size + info.hblkhd + info.arena)); |
|
574 |
#endif
|
|
575 |
||
576 |
puts(""); |
|
577 |
}
|
|
578 |
||
579 |
||
580 |
#ifndef DBUG_OFF
|
|
581 |
#ifdef EXTRA_DEBUG_DUMP_TABLE_LISTS
|
|
582 |
||
583 |
||
584 |
/*
|
|
585 |
A fixed-size FIFO pointer queue that also doesn't allow one to put an
|
|
586 |
element that has previously been put into it.
|
|
587 |
|
|
588 |
There is a hard-coded limit of the total number of queue put operations.
|
|
589 |
The implementation is trivial and is intended for use in debug dumps only.
|
|
590 |
*/
|
|
591 |
||
592 |
template <class T> class Unique_fifo_queue |
|
593 |
{
|
|
594 |
public: |
|
595 |
/* Add an element to the queue */
|
|
596 |
void push_back(T *tbl) |
|
597 |
{
|
|
598 |
if (!tbl) |
|
599 |
return; |
|
600 |
// check if we've already scheduled and/or dumped the element
|
|
601 |
for (int i= 0; i < last; i++) |
|
602 |
{
|
|
603 |
if (elems[i] == tbl) |
|
604 |
return; |
|
605 |
}
|
|
606 |
elems[last++]= tbl; |
|
607 |
}
|
|
608 |
||
609 |
bool pop_first(T **elem) |
|
610 |
{
|
|
611 |
if (first < last) |
|
612 |
{
|
|
613 |
*elem= elems[first++]; |
|
614 |
return TRUE; |
|
615 |
}
|
|
616 |
return FALSE; |
|
617 |
}
|
|
618 |
||
619 |
void reset() |
|
620 |
{
|
|
621 |
first= last= 0; |
|
622 |
}
|
|
623 |
enum { MAX_ELEMS=1000}; |
|
624 |
T *elems[MAX_ELEMS]; |
|
625 |
int first; // First undumped table |
|
626 |
int last; // Last undumped element |
|
627 |
};
|
|
628 |
||
629 |
class Dbug_table_list_dumper |
|
630 |
{
|
|
631 |
FILE *out; |
|
632 |
Unique_fifo_queue<TABLE_LIST> tables_fifo; |
|
633 |
Unique_fifo_queue<List<TABLE_LIST> > tbl_lists; |
|
634 |
public: |
|
635 |
void dump_one_struct(TABLE_LIST *tbl); |
|
636 |
||
637 |
int dump_graph(st_select_lex *select_lex, TABLE_LIST *first_leaf); |
|
638 |
};
|
|
639 |
||
640 |
||
641 |
void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl) |
|
642 |
{
|
|
643 |
Dbug_table_list_dumper dumper; |
|
644 |
dumper.dump_graph(select_lex, tl); |
|
645 |
}
|
|
646 |
||
647 |
||
648 |
/*
|
|
649 |
- Dump one TABLE_LIST objects and its outgoing edges
|
|
650 |
- Schedule that other objects seen along the edges are dumped too.
|
|
651 |
*/
|
|
652 |
||
653 |
void Dbug_table_list_dumper::dump_one_struct(TABLE_LIST *tbl) |
|
654 |
{
|
|
655 |
fprintf(out, "\"%p\" [\n", tbl); |
|
656 |
fprintf(out, " label = \"%p|", tbl); |
|
657 |
fprintf(out, "alias=%s|", tbl->alias? tbl->alias : "NULL"); |
|
658 |
fprintf(out, "<next_leaf>next_leaf=%p|", tbl->next_leaf); |
|
659 |
fprintf(out, "<next_local>next_local=%p|", tbl->next_local); |
|
660 |
fprintf(out, "<next_global>next_global=%p|", tbl->next_global); |
|
661 |
fprintf(out, "<embedding>embedding=%p", tbl->embedding); |
|
662 |
||
663 |
if (tbl->nested_join) |
|
664 |
fprintf(out, "|<nested_j>nested_j=%p", tbl->nested_join); |
|
665 |
if (tbl->join_list) |
|
666 |
fprintf(out, "|<join_list>join_list=%p", tbl->join_list); |
|
667 |
if (tbl->on_expr) |
|
668 |
fprintf(out, "|<on_expr>on_expr=%p", tbl->on_expr); |
|
669 |
fprintf(out, "\"\n"); |
|
670 |
fprintf(out, " shape = \"record\"\n];\n\n"); |
|
671 |
||
672 |
if (tbl->next_leaf) |
|
673 |
{
|
|
674 |
fprintf(out, "\n\"%p\":next_leaf -> \"%p\"[ color = \"#000000\" ];\n", |
|
675 |
tbl, tbl->next_leaf); |
|
676 |
tables_fifo.push_back(tbl->next_leaf); |
|
677 |
}
|
|
678 |
if (tbl->next_local) |
|
679 |
{
|
|
680 |
fprintf(out, "\n\"%p\":next_local -> \"%p\"[ color = \"#404040\" ];\n", |
|
681 |
tbl, tbl->next_local); |
|
682 |
tables_fifo.push_back(tbl->next_local); |
|
683 |
}
|
|
684 |
if (tbl->next_global) |
|
685 |
{
|
|
686 |
fprintf(out, "\n\"%p\":next_global -> \"%p\"[ color = \"#808080\" ];\n", |
|
687 |
tbl, tbl->next_global); |
|
688 |
tables_fifo.push_back(tbl->next_global); |
|
689 |
}
|
|
690 |
||
691 |
if (tbl->embedding) |
|
692 |
{
|
|
693 |
fprintf(out, "\n\"%p\":embedding -> \"%p\"[ color = \"#FF0000\" ];\n", |
|
694 |
tbl, tbl->embedding); |
|
695 |
tables_fifo.push_back(tbl->embedding); |
|
696 |
}
|
|
697 |
||
698 |
if (tbl->join_list) |
|
699 |
{
|
|
700 |
fprintf(out, "\n\"%p\":join_list -> \"%p\"[ color = \"#0000FF\" ];\n", |
|
701 |
tbl, tbl->join_list); |
|
702 |
tbl_lists.push_back(tbl->join_list); |
|
703 |
}
|
|
704 |
}
|
|
705 |
||
706 |
||
707 |
int Dbug_table_list_dumper::dump_graph(st_select_lex *select_lex, |
|
708 |
TABLE_LIST *first_leaf) |
|
709 |
{
|
|
710 |
DBUG_ENTER("Dbug_table_list_dumper::dump_graph"); |
|
711 |
char filename[500]; |
|
712 |
int no = 0; |
|
713 |
do
|
|
714 |
{
|
|
715 |
sprintf(filename, "tlist_tree%.3d.g", no); |
|
716 |
if ((out= fopen(filename, "rt"))) |
|
717 |
{
|
|
718 |
/* File exists, try next name */
|
|
719 |
fclose(out); |
|
720 |
}
|
|
721 |
no++; |
|
722 |
} while (out); |
|
723 |
||
724 |
/* Ok, found an unoccupied name, create the file */
|
|
725 |
if (!(out= fopen(filename, "wt"))) |
|
726 |
{
|
|
727 |
DBUG_PRINT("tree_dump", ("Failed to create output file")); |
|
728 |
DBUG_RETURN(1); |
|
729 |
}
|
|
730 |
||
731 |
DBUG_PRINT("tree_dump", ("dumping tree to %s", filename)); |
|
732 |
||
733 |
fputs("digraph g {\n", out); |
|
734 |
fputs("graph [", out); |
|
735 |
fputs(" rankdir = \"LR\"", out); |
|
736 |
fputs("];", out); |
|
737 |
||
738 |
TABLE_LIST *tbl; |
|
739 |
tables_fifo.reset(); |
|
740 |
dump_one_struct(first_leaf); |
|
741 |
while (tables_fifo.pop_first(&tbl)) |
|
742 |
{
|
|
743 |
dump_one_struct(tbl); |
|
744 |
}
|
|
745 |
||
746 |
List<TABLE_LIST> *plist; |
|
747 |
tbl_lists.push_back(&select_lex->top_join_list); |
|
748 |
while (tbl_lists.pop_first(&plist)) |
|
749 |
{
|
|
750 |
fprintf(out, "\"%p\" [\n", plist); |
|
751 |
fprintf(out, " bgcolor = \"\""); |
|
752 |
fprintf(out, " label = \"L %p\"", plist); |
|
753 |
fprintf(out, " shape = \"record\"\n];\n\n"); |
|
754 |
}
|
|
755 |
||
756 |
fprintf(out, " { rank = same; "); |
|
757 |
for (TABLE_LIST *tl=first_leaf; tl; tl= tl->next_leaf) |
|
758 |
fprintf(out, " \"%p\"; ", tl); |
|
759 |
fprintf(out, "};\n"); |
|
760 |
fputs("}", out); |
|
761 |
fclose(out); |
|
762 |
||
763 |
char filename2[500]; |
|
764 |
filename[strlen(filename) - 1]= 0; |
|
765 |
filename[strlen(filename) - 1]= 0; |
|
766 |
sprintf(filename2, "%s.query", filename); |
|
767 |
||
768 |
if ((out= fopen(filename2, "wt"))) |
|
769 |
{
|
|
770 |
fprintf(out, "%s", current_thd->query); |
|
771 |
fclose(out); |
|
772 |
}
|
|
773 |
DBUG_RETURN(0); |
|
774 |
}
|
|
775 |
||
776 |
#endif
|
|
777 |
||
778 |
#endif
|
|
779 |