~vlad-lesin/percona-server/mysql-5.0.33-original

« back to all changes in this revision

Viewing changes to sql/sql_test.cc

  • Committer: Vlad Lesin
  • Date: 2012-07-31 09:21:34 UTC
  • Revision ID: vladislav.lesin@percona.com-20120731092134-zfodx022b7992wsi
VirginĀ 5.0.33

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or
 
6
   (at your option) any later version.
 
7
 
 
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.
 
12
 
 
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 */
 
16
 
 
17
 
 
18
/* Write some debug info */
 
19
 
 
20
 
 
21
#include "mysql_priv.h"
 
22
#include "sql_select.h"
 
23
#include <hash.h>
 
24
#include <thr_alarm.h>
 
25
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
 
26
#include <malloc.h>
 
27
#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H)
 
28
#include <sys/malloc.h>
 
29
#endif
 
30
 
 
31
static const char *lock_descriptions[] =
 
32
{
 
33
  "No lock",
 
34
  "Low priority read lock",
 
35
  "Shared 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"
 
45
};
 
46
 
 
47
 
 
48
#ifndef DBUG_OFF
 
49
 
 
50
void
 
51
print_where(COND *cond,const char *info)
 
52
{
 
53
  if (cond)
 
54
  {
 
55
    char buff[256];
 
56
    String str(buff,(uint32) sizeof(buff), system_charset_info);
 
57
    str.length(0);
 
58
    cond->print(&str);
 
59
    str.append('\0');
 
60
    DBUG_LOCK_FILE;
 
61
    (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
 
62
    (void) fputs(str.ptr(),DBUG_FILE);
 
63
    (void) fputc('\n',DBUG_FILE);
 
64
    DBUG_UNLOCK_FILE;
 
65
  }
 
66
}
 
67
        /* This is for debugging purposes */
 
68
 
 
69
 
 
70
void print_cached_tables(void)
 
71
{
 
72
  uint idx,count,unused;
 
73
  TABLE *start_link,*lnk;
 
74
 
 
75
  VOID(pthread_mutex_lock(&LOCK_open));
 
76
  puts("DB             Table                            Version  Thread  L.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%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");
 
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
  return;
 
113
}
 
114
 
 
115
 
 
116
void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
 
117
{
 
118
  char buff[256],buff2[256];
 
119
  String str(buff,sizeof(buff),system_charset_info);
 
120
  String out(buff2,sizeof(buff2),system_charset_info);
 
121
  const char *sep;
 
122
  DBUG_ENTER("TEST_filesort");
 
123
 
 
124
  out.length(0);
 
125
  for (sep=""; s_length-- ; sortorder++, sep=" ")
 
126
  {
 
127
    out.append(sep);
 
128
    if (sortorder->reverse)
 
129
      out.append('-');
 
130
    if (sortorder->field)
 
131
    {
 
132
      if (sortorder->field->table_name)
 
133
      {
 
134
        out.append(*sortorder->field->table_name);
 
135
        out.append('.');
 
136
      }
 
137
      out.append(sortorder->field->field_name ? sortorder->field->field_name:
 
138
                 "tmp_table_column");
 
139
    }
 
140
    else
 
141
    {
 
142
      str.length(0);
 
143
      sortorder->item->print(&str);
 
144
      out.append(str);
 
145
    }
 
146
  }
 
147
  out.append('\0');                             // Purify doesn't like c_ptr()
 
148
  DBUG_LOCK_FILE;
 
149
  VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
 
150
  fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
 
151
  DBUG_UNLOCK_FILE;
 
152
  DBUG_VOID_RETURN;
 
153
}
 
154
 
 
155
 
 
156
void
 
157
TEST_join(JOIN *join)
 
158
{
 
159
  uint i,ref;
 
160
  DBUG_ENTER("TEST_join");
 
161
 
 
162
  DBUG_LOCK_FILE;
 
163
  VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
 
164
  for (i=0 ; i < join->tables ; i++)
 
165
  {
 
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",
 
170
            form->alias,
 
171
            join_type_str[tab->type],
 
172
            tab->keys.print(key_map_buff),
 
173
            tab->ref.key_parts,
 
174
            tab->ref.key,
 
175
            tab->ref.key_length);
 
176
    if (tab->select)
 
177
    {
 
178
      char buf[MAX_KEY/8+1];
 
179
      if (tab->use_quick == 2)
 
180
        fprintf(DBUG_FILE,
 
181
                "                  quick select checked for each record (keys: %s)\n",
 
182
                tab->select->quick_keys.print(buf));
 
183
      else if (tab->select->quick)
 
184
      {
 
185
        fprintf(DBUG_FILE, "                  quick select used:\n");
 
186
        tab->select->quick->dbug_dump(18, FALSE);
 
187
      }
 
188
      else
 
189
        VOID(fputs("                  select used\n",DBUG_FILE));
 
190
    }
 
191
    if (tab->ref.key_parts)
 
192
    {
 
193
      VOID(fputs("                  refs: ",DBUG_FILE));
 
194
      for (ref=0 ; ref < tab->ref.key_parts ; ref++)
 
195
      {
 
196
        Item *item=tab->ref.items[ref];
 
197
        fprintf(DBUG_FILE,"%s  ", item->full_name());
 
198
      }
 
199
      VOID(fputc('\n',DBUG_FILE));
 
200
    }
 
201
  }
 
202
  DBUG_UNLOCK_FILE;
 
203
  DBUG_VOID_RETURN;
 
204
}
 
205
 
 
206
 
 
207
/* 
 
208
  Print the current state during query optimization.
 
209
 
 
210
  SYNOPSIS
 
211
    print_plan()
 
212
    join         pointer to the structure providing all context info for
 
213
                 the query
 
214
    read_time    the cost of the best partial plan
 
215
    record_count estimate for the number of records returned by the best
 
216
                 partial plan
 
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
 
220
 
 
221
  DESCRIPTION
 
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,
 
225
    record_count).
 
226
    Useful to trace query optimizer functions.
 
227
 
 
228
  RETURN
 
229
    None
 
230
*/
 
231
 
 
232
void
 
233
print_plan(JOIN* join, uint idx, double record_count, double read_time,
 
234
           double current_read_time, const char *info)
 
235
{
 
236
  uint i;
 
237
  POSITION pos;
 
238
  JOIN_TAB *join_table;
 
239
  JOIN_TAB **plan_nodes;
 
240
  TABLE*   table;
 
241
 
 
242
  if (info == 0)
 
243
    info= "";
 
244
 
 
245
  DBUG_LOCK_FILE;
 
246
  if (join->best_read == DBL_MAX)
 
247
  {
 
248
    fprintf(DBUG_FILE,
 
249
    "%s; idx:%u, best: DBL_MAX, atime: %g, itime: %g, count: %g\n",
 
250
    info, idx, current_read_time, read_time, record_count);
 
251
  }
 
252
  else
 
253
  {
 
254
    fprintf(DBUG_FILE,
 
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);
 
257
  }
 
258
 
 
259
  /* Print the tables in JOIN->positions */
 
260
  fputs("     POSITIONS: ", DBUG_FILE);
 
261
  for (i= 0; i < idx ; i++)
 
262
  {
 
263
    pos = join->positions[i];
 
264
    table= pos.table->table;
 
265
    if (table)
 
266
      fputs(table->s->table_name, DBUG_FILE);
 
267
    fputc(' ', DBUG_FILE);
 
268
  }
 
269
  fputc('\n', DBUG_FILE);
 
270
 
 
271
  /*
 
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'.
 
274
  */
 
275
  if (join->best_read < DBL_MAX)
 
276
  {
 
277
    fputs("BEST_POSITIONS: ", DBUG_FILE);
 
278
    for (i= 0; i < idx ; i++)
 
279
    {
 
280
      pos= join->best_positions[i];
 
281
      table= pos.table->table;
 
282
      if (table)
 
283
        fputs(table->s->table_name, DBUG_FILE);
 
284
      fputc(' ', DBUG_FILE);
 
285
    }
 
286
  }
 
287
  fputc('\n', DBUG_FILE);
 
288
 
 
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++)
 
292
  {
 
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);
 
300
  }
 
301
  fputc('\n', DBUG_FILE);
 
302
 
 
303
  DBUG_UNLOCK_FILE;
 
304
}
 
305
 
 
306
#endif
 
307
 
 
308
typedef struct st_debug_lock
 
309
{
 
310
  ulong thread_id;
 
311
  char table_name[FN_REFLEN];
 
312
  bool waiting;
 
313
  const char *lock_text;
 
314
  enum thr_lock_type type;
 
315
} TABLE_LOCK_INFO;
 
316
 
 
317
static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b)
 
318
{
 
319
  if (a->thread_id > b->thread_id)
 
320
    return 1;
 
321
  if (a->thread_id < b->thread_id)
 
322
    return -1;
 
323
  if (a->waiting == b->waiting)
 
324
    return 0;
 
325
  else if (a->waiting)
 
326
    return -1;
 
327
  return 1;
 
328
}
 
329
 
 
330
 
 
331
static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
 
332
                                  bool wait, const char *text)
 
333
{
 
334
  if (data)
 
335
  {
 
336
    TABLE *table=(TABLE *)data->debug_print_param;
 
337
    if (table && table->s->tmp_table == NO_TMP_TABLE)
 
338
    {
 
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));
 
349
    }
 
350
  }
 
351
}
 
352
 
 
353
 
 
354
/*
 
355
  Regarding MERGE tables:
 
356
 
 
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.
 
360
 
 
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.
 
366
*/
 
367
 
 
368
static void display_table_locks(void) 
 
369
{
 
370
  LIST *list;
 
371
  DYNAMIC_ARRAY saved_table_locks;
 
372
 
 
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))
 
376
  {
 
377
    THR_LOCK *lock=(THR_LOCK*) list->data;
 
378
 
 
379
    VOID(pthread_mutex_lock(&lock->mutex));
 
380
    push_locks_into_array(&saved_table_locks, lock->write.data, FALSE,
 
381
                          "Locked - write");
 
382
    push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE,
 
383
                          "Waiting - write");
 
384
    push_locks_into_array(&saved_table_locks, lock->read.data, FALSE,
 
385
                          "Locked - read");
 
386
    push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE,
 
387
                          "Waiting - read");
 
388
    VOID(pthread_mutex_unlock(&lock->mutex));
 
389
  }
 
390
  VOID(pthread_mutex_unlock(&THR_LOCK_lock));
 
391
  if (!saved_table_locks.elements) goto end;
 
392
  
 
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);
 
395
 
 
396
  puts("\nThread database.table_name          Locked/Waiting        Lock_type\n");
 
397
  
 
398
  unsigned int i;
 
399
  for (i=0 ; i < saved_table_locks.elements ; i++)
 
400
  {
 
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]);
 
404
  }
 
405
  puts("\n\n");
 
406
end:
 
407
  delete_dynamic(&saved_table_locks);
 
408
}
 
409
 
 
410
 
 
411
static int print_key_cache_status(const char *name, KEY_CACHE *key_cache)
 
412
{
 
413
  char llbuff1[22];
 
414
  char llbuff2[22];
 
415
  char llbuff3[22];
 
416
  char llbuff4[22];
 
417
 
 
418
  if (!key_cache->key_cache_inited)
 
419
  {
 
420
    printf("%s: Not in use\n", name);
 
421
  }
 
422
  else
 
423
  {
 
424
    printf("%s\n\
 
425
Buffer_size:    %10lu\n\
 
426
Block_size:     %10lu\n\
 
427
Division_limit: %10lu\n\
 
428
Age_limit:      %10lu\n\
 
429
blocks used:    %10lu\n\
 
430
not flushed:    %10lu\n\
 
431
w_requests:     %10s\n\
 
432
writes:         %10s\n\
 
433
r_requests:     %10s\n\
 
434
reads:          %10s\n\n",
 
435
           name,
 
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));
 
443
  }
 
444
  return 0;
 
445
}
 
446
 
 
447
 
 
448
void mysql_print_status()
 
449
{
 
450
  char current_dir[FN_REFLEN];
 
451
  STATUS_VAR tmp;
 
452
 
 
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
 
460
#ifndef DBUG_OFF
 
461
  print_cached_tables();
 
462
#endif
 
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\
 
468
read_key:   %10lu\n\
 
469
read_next:  %10lu\n\
 
470
read_rnd    %10lu\n\
 
471
read_first: %10lu\n\
 
472
write:      %10lu\n\
 
473
delete      %10lu\n\
 
474
update:     %10lu\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,
 
479
         tmp.ha_write_count,
 
480
         tmp.ha_delete_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\
 
486
Open files:    %10lu\n\
 
487
Open streams:  %10lu\n",
 
488
         tmp.opened_tables,
 
489
         (ulong) cached_tables(),
 
490
         (ulong) my_file_opened,
 
491
         (ulong) my_stream_opened);
 
492
 
 
493
  ALARM_INFO alarm_info;
 
494
#ifndef DONT_USE_THR_ALARM
 
495
  thr_alarm_info(&alarm_info);
 
496
  printf("\nAlarm status:\n\
 
497
Active alarms:   %u\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);
 
503
#endif
 
504
  display_table_locks();
 
505
  fflush(stdout);
 
506
  my_checkmalloc();
 
507
  TERMINATE(stdout);                            // Write malloc information
 
508
 
 
509
#ifdef HAVE_MALLINFO
 
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",
 
523
         (int) info.arena       ,
 
524
         (int) info.ordblks,
 
525
         (int) info.smblks,
 
526
         (int) info.hblks,
 
527
         (int) info.hblkhd,
 
528
         (int) info.usmblks,
 
529
         (int) info.fsmblks,
 
530
         (int) info.uordblks,
 
531
         (int) info.fordblks,
 
532
         (int) info.keepcost,
 
533
         (long) (thread_count * thread_stack + info.hblkhd + info.arena));
 
534
#endif
 
535
  puts("");
 
536
}