~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to storage/myisam/myisamlog.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* write whats in isam.log */
 
17
 
 
18
#ifndef USE_MY_FUNC
 
19
#define USE_MY_FUNC
 
20
#endif
 
21
 
 
22
#include "myisamdef.h"
 
23
#include <my_tree.h>
 
24
#include <stdarg.h>
 
25
#ifdef HAVE_GETRUSAGE
 
26
#include <sys/resource.h>
 
27
#endif
 
28
 
 
29
#define FILENAME(A) (A ? A->show_name : "Unknown")
 
30
 
 
31
struct file_info {
 
32
  long process;
 
33
  int  filenr,id;
 
34
  uint rnd;
 
35
  char *name, *show_name;
 
36
  uchar *record;
 
37
  MI_INFO *isam;
 
38
  my_bool closed, used;
 
39
  ulong accessed;
 
40
};
 
41
 
 
42
struct test_if_open_param {
 
43
  char * name;
 
44
  int max_id;
 
45
};
 
46
 
 
47
struct st_access_param
 
48
{
 
49
  ulong min_accessed;
 
50
  struct file_info *found;
 
51
};
 
52
 
 
53
#define NO_FILEPOS (ulong) ~0L
 
54
 
 
55
extern int main(int argc,char * *argv);
 
56
static void get_options(int *argc,char ***argv);
 
57
static int examine_log(char * file_name,char **table_names);
 
58
static int read_string(IO_CACHE *file,uchar* *to,uint length);
 
59
static int file_info_compare(void *cmp_arg, void *a,void *b);
 
60
static int test_if_open(struct file_info *key,element_count count,
 
61
                        struct test_if_open_param *param);
 
62
static void fix_blob_pointers(MI_INFO *isam,uchar *record);
 
63
static int test_when_accessed(struct file_info *key,element_count count,
 
64
                              struct st_access_param *access_param);
 
65
static void file_info_free(struct file_info *info);
 
66
static int close_some_file(TREE *tree);
 
67
static int reopen_closed_file(TREE *tree,struct file_info *file_info);
 
68
static int find_record_with_key(struct file_info *file_info,uchar *record);
 
69
static void printf_log(const char *str,...);
 
70
static my_bool cmp_filename(struct file_info *file_info,char * name);
 
71
 
 
72
static uint verbose=0,update=0,test_info=0,max_files=0,re_open_count=0,
 
73
  recover=0,prefix_remove=0,opt_processes=0;
 
74
static char *log_filename=0, *filepath=0, *write_filename=0;
 
75
static char *record_pos_file= 0;
 
76
static ulong com_count[10][3],number_of_commands=(ulong) ~0L,
 
77
             isamlog_process;
 
78
static my_off_t isamlog_filepos,start_offset=0,record_pos= HA_OFFSET_ERROR;
 
79
static const char *command_name[]=
 
80
{"open","write","update","delete","close","extra","lock","re-open",
 
81
 "delete-all", NullS};
 
82
 
 
83
 
 
84
int main(int argc, char **argv)
 
85
{
 
86
  int error,i,first;
 
87
  ulong total_count,total_error,total_recover;
 
88
  MY_INIT(argv[0]);
 
89
 
 
90
  log_filename=myisam_log_filename;
 
91
  get_options(&argc,&argv);
 
92
  /* Number of MyISAM files we can have open at one time */
 
93
  max_files= (my_set_max_open_files(min(max_files,8))-6)/2;
 
94
  if (update)
 
95
    printf("Trying to %s MyISAM files according to log '%s'\n",
 
96
           (recover ? "recover" : "update"),log_filename);
 
97
  error= examine_log(log_filename,argv);
 
98
  if (update && ! error)
 
99
    puts("Tables updated successfully");
 
100
  total_count=total_error=total_recover=0;
 
101
  for (i=first=0 ; command_name[i] ; i++)
 
102
  {
 
103
    if (com_count[i][0])
 
104
    {
 
105
      if (!first++)
 
106
      {
 
107
        if (verbose || update)
 
108
          puts("");
 
109
        puts("Commands   Used count    Errors   Recover errors");
 
110
      }
 
111
      printf("%-12s%9ld%10ld%17ld\n",command_name[i],com_count[i][0],
 
112
             com_count[i][1],com_count[i][2]);
 
113
      total_count+=com_count[i][0];
 
114
      total_error+=com_count[i][1];
 
115
      total_recover+=com_count[i][2];
 
116
    }
 
117
  }
 
118
  if (total_count)
 
119
    printf("%-12s%9ld%10ld%17ld\n","Total",total_count,total_error,
 
120
           total_recover);
 
121
  if (re_open_count)
 
122
    printf("Had to do %d re-open because of too few possibly open files\n",
 
123
           re_open_count);
 
124
  VOID(mi_panic(HA_PANIC_CLOSE));
 
125
  my_free_open_file_info();
 
126
  my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
 
127
  exit(error);
 
128
  return 0;                             /* No compiler warning */
 
129
} /* main */
 
130
 
 
131
 
 
132
static void get_options(register int *argc, register char ***argv)
 
133
{
 
134
  int help,version;
 
135
  const char *pos,*usage;
 
136
  char option;
 
137
 
 
138
  help=0;
 
139
  usage="Usage: %s [-?iruvDIV] [-c #] [-f #] [-F filepath/] [-o #] [-R file recordpos] [-w write_file] [log-filename [table ...]] \n";
 
140
  pos="";
 
141
 
 
142
  while (--*argc > 0 && *(pos = *(++*argv)) == '-' ) {
 
143
    while (*++pos)
 
144
    {
 
145
      version=0;
 
146
      switch((option=*pos)) {
 
147
      case '#':
 
148
        DBUG_PUSH (++pos);
 
149
        pos=" ";                                /* Skip rest of arg */
 
150
        break;
 
151
      case 'c':
 
152
        if (! *++pos)
 
153
        {
 
154
          if (!--*argc)
 
155
            goto err;
 
156
          else
 
157
            pos= *(++*argv);
 
158
        }
 
159
        number_of_commands=(ulong) atol(pos);
 
160
        pos=" ";
 
161
        break;
 
162
      case 'u':
 
163
        update=1;
 
164
        break;
 
165
      case 'f':
 
166
        if (! *++pos)
 
167
        {
 
168
          if (!--*argc)
 
169
            goto err;
 
170
          else
 
171
            pos= *(++*argv);
 
172
        }
 
173
        max_files=(uint) atoi(pos);
 
174
        pos=" ";
 
175
        break;
 
176
      case 'i':
 
177
        test_info=1;
 
178
        break;
 
179
      case 'o':
 
180
        if (! *++pos)
 
181
        {
 
182
          if (!--*argc)
 
183
            goto err;
 
184
          else
 
185
            pos= *(++*argv);
 
186
        }
 
187
        start_offset=(my_off_t) strtoll(pos,NULL,10);
 
188
        pos=" ";
 
189
        break;
 
190
      case 'p':
 
191
        if (! *++pos)
 
192
        {
 
193
          if (!--*argc)
 
194
            goto err;
 
195
          else
 
196
            pos= *(++*argv);
 
197
        }
 
198
        prefix_remove=atoi(pos);
 
199
        break;
 
200
      case 'r':
 
201
        update=1;
 
202
        recover++;
 
203
        break;
 
204
      case 'P':
 
205
        opt_processes=1;
 
206
        break;
 
207
      case 'R':
 
208
        if (! *++pos)
 
209
        {
 
210
          if (!--*argc)
 
211
            goto err;
 
212
          else
 
213
            pos= *(++*argv);
 
214
        }
 
215
        record_pos_file=(char*) pos;
 
216
        if (!--*argc)
 
217
          goto err;
 
218
        record_pos=(my_off_t) strtoll(*(++*argv),NULL,10);
 
219
        pos=" ";
 
220
        break;
 
221
      case 'v':
 
222
        verbose++;
 
223
        break;
 
224
      case 'w':
 
225
        if (! *++pos)
 
226
        {
 
227
          if (!--*argc)
 
228
            goto err;
 
229
          else
 
230
            pos= *(++*argv);
 
231
        }
 
232
        write_filename=(char*) pos;
 
233
        pos=" ";
 
234
        break;
 
235
      case 'F':
 
236
        if (! *++pos)
 
237
        {
 
238
          if (!--*argc)
 
239
            goto err;
 
240
          else
 
241
            pos= *(++*argv);
 
242
        }
 
243
        filepath= (char*) pos;
 
244
        pos=" ";
 
245
        break;
 
246
      case 'V':
 
247
        version=1;
 
248
        /* Fall through */
 
249
      case 'I':
 
250
      case '?':
 
251
#include <help_start.h>
 
252
        printf("%s  Ver 1.4 for %s at %s\n",my_progname,SYSTEM_TYPE,
 
253
               MACHINE_TYPE);
 
254
        puts("By Monty, for your professional use\n");
 
255
        if (version)
 
256
          break;
 
257
        puts("Write info about whats in a MyISAM log file.");
 
258
        printf("If no file name is given %s is used\n",log_filename);
 
259
        puts("");
 
260
        printf(usage,my_progname);
 
261
        puts("");
 
262
        puts("Options: -? or -I \"Info\"     -V \"version\"   -c \"do only # commands\"");
 
263
        puts("         -f \"max open files\" -F \"filepath\"  -i \"extra info\"");
 
264
        puts("         -o \"offset\"         -p # \"remove # components from path\"");
 
265
        puts("         -r \"recover\"        -R \"file recordposition\"");
 
266
        puts("         -u \"update\"         -v \"verbose\"   -w \"write file\"");
 
267
        puts("         -D \"myisam compiled with DBUG\"   -P \"processes\"");
 
268
        puts("\nOne can give a second and a third '-v' for more verbose.");
 
269
        puts("Normaly one does a update (-u).");
 
270
        puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted.");
 
271
        puts("If one gives table names as arguments only these tables will be updated\n");
 
272
        help=1;
 
273
#include <help_end.h>
 
274
        break;
 
275
      default:
 
276
        printf("illegal option: \"-%c\"\n",*pos);
 
277
        break;
 
278
      }
 
279
    }
 
280
  }
 
281
  if (! *argc)
 
282
  {
 
283
    if (help)
 
284
    exit(0);
 
285
    (*argv)++;
 
286
  }
 
287
  if (*argc >= 1)
 
288
  {
 
289
    log_filename=(char*) pos;
 
290
    (*argc)--;
 
291
    (*argv)++;
 
292
  }
 
293
  return;
 
294
 err:
 
295
  VOID(fprintf(stderr,"option \"%c\" used without or with wrong argument\n",
 
296
               option));
 
297
  exit(1);
 
298
}
 
299
 
 
300
 
 
301
static int examine_log(char * file_name, char **table_names)
 
302
{
 
303
  uint command,result,files_open;
 
304
  ulong access_time,length;
 
305
  my_off_t filepos;
 
306
  int lock_command,mi_result;
 
307
  char isam_file_name[FN_REFLEN],llbuff[21],llbuff2[21];
 
308
  uchar head[20];
 
309
  uchar*        buff;
 
310
  struct test_if_open_param open_param;
 
311
  IO_CACHE cache;
 
312
  File file;
 
313
  FILE *write_file;
 
314
  enum ha_extra_function extra_command;
 
315
  TREE tree;
 
316
  struct file_info file_info,*curr_file_info;
 
317
  DBUG_ENTER("examine_log");
 
318
 
 
319
  if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0)
 
320
    DBUG_RETURN(1);
 
321
  write_file=0;
 
322
  if (write_filename)
 
323
  {
 
324
    if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME))))
 
325
    {
 
326
      my_close(file,MYF(0));
 
327
      DBUG_RETURN(1);
 
328
    }
 
329
  }
 
330
 
 
331
  init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
 
332
  bzero((uchar*) com_count,sizeof(com_count));
 
333
  init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1,
 
334
            (tree_element_free) file_info_free, NULL);
 
335
  VOID(init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,KEY_CACHE_SIZE,
 
336
                      0, 0));
 
337
 
 
338
  files_open=0; access_time=0;
 
339
  while (access_time++ != number_of_commands &&
 
340
         !my_b_read(&cache,(uchar*) head,9))
 
341
  {
 
342
    isamlog_filepos=my_b_tell(&cache)-9L;
 
343
    file_info.filenr= mi_uint2korr(head+1);
 
344
    isamlog_process=file_info.process=(long) mi_uint4korr(head+3);
 
345
    if (!opt_processes)
 
346
      file_info.process=0;
 
347
    result= mi_uint2korr(head+7);
 
348
    if ((curr_file_info=(struct file_info*) tree_search(&tree, &file_info,
 
349
                                                        tree.custom_arg)))
 
350
    {
 
351
      curr_file_info->accessed=access_time;
 
352
      if (update && curr_file_info->used && curr_file_info->closed)
 
353
      {
 
354
        if (reopen_closed_file(&tree,curr_file_info))
 
355
        {
 
356
          command=sizeof(com_count)/sizeof(com_count[0][0])/3;
 
357
          result=0;
 
358
          goto com_err;
 
359
        }
 
360
      }
 
361
    }
 
362
    command=(uint) head[0];
 
363
    if (command < sizeof(com_count)/sizeof(com_count[0][0])/3 &&
 
364
        (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
365
    {
 
366
      com_count[command][0]++;
 
367
      if (result)
 
368
        com_count[command][1]++;
 
369
    }
 
370
    switch ((enum myisam_log_commands) command) {
 
371
    case MI_LOG_OPEN:
 
372
      if (!table_names[0])
 
373
      {
 
374
        com_count[command][0]--;                /* Must be counted explicite */
 
375
        if (result)
 
376
          com_count[command][1]--;
 
377
      }
 
378
 
 
379
      if (curr_file_info)
 
380
        printf("\nWarning: %s is opened with same process and filenumber\n"
 
381
               "Maybe you should use the -P option ?\n",
 
382
               curr_file_info->show_name);
 
383
      if (my_b_read(&cache,(uchar*) head,2))
 
384
        goto err;
 
385
      file_info.name=0;
 
386
      file_info.show_name=0;
 
387
      file_info.record=0;
 
388
      if (read_string(&cache,(uchar**) &file_info.name,
 
389
                      (uint) mi_uint2korr(head)))
 
390
        goto err;
 
391
      {
 
392
        uint i;
 
393
        char *pos,*to;
 
394
 
 
395
        /* Fix if old DOS files to new format */
 
396
        for (pos=file_info.name; (pos=strchr(pos,'\\')) ; pos++)
 
397
          *pos= '/';
 
398
 
 
399
        pos=file_info.name;
 
400
        for (i=0 ; i < prefix_remove ; i++)
 
401
        {
 
402
          char *next;
 
403
          if (!(next=strchr(pos,'/')))
 
404
            break;
 
405
          pos=next+1;
 
406
        }
 
407
        to=isam_file_name;
 
408
        if (filepath)
 
409
          to=convert_dirname(isam_file_name,filepath,NullS);
 
410
        strmov(to,pos);
 
411
        fn_ext(isam_file_name)[0]=0;    /* Remove extension */
 
412
      }
 
413
      open_param.name=file_info.name;
 
414
      open_param.max_id=0;
 
415
      VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param,
 
416
                     left_root_right));
 
417
      file_info.id=open_param.max_id+1;
 
418
      /*
 
419
       * In the line below +10 is added to accomodate '<' and '>' chars
 
420
       * plus '\0' at the end, so that there is place for 7 digits.
 
421
       * It is  improbable that same table can have that many entries in 
 
422
       * the table cache.
 
423
       * The additional space is needed for the sprintf commands two lines
 
424
       * below.
 
425
       */ 
 
426
      file_info.show_name=my_memdup(isam_file_name,
 
427
                                    (uint) strlen(isam_file_name)+10,
 
428
                                    MYF(MY_WME));
 
429
      if (file_info.id > 1)
 
430
        sprintf(strend(file_info.show_name),"<%d>",file_info.id);
 
431
      file_info.closed=1;
 
432
      file_info.accessed=access_time;
 
433
      file_info.used=1;
 
434
      if (table_names[0])
 
435
      {
 
436
        char **name;
 
437
        file_info.used=0;
 
438
        for (name=table_names ; *name ; name++)
 
439
        {
 
440
          if (!strcmp(*name,isam_file_name))
 
441
            file_info.used=1;                   /* Update/log only this */
 
442
        }
 
443
      }
 
444
      if (update && file_info.used)
 
445
      {
 
446
        if (files_open >= max_files)
 
447
        {
 
448
          if (close_some_file(&tree))
 
449
            goto com_err;
 
450
          files_open--;
 
451
        }
 
452
        if (!(file_info.isam= mi_open(isam_file_name,O_RDWR,
 
453
                                      HA_OPEN_WAIT_IF_LOCKED)))
 
454
          goto com_err;
 
455
        if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength,
 
456
                                         MYF(MY_WME))))
 
457
          goto end;
 
458
        files_open++;
 
459
        file_info.closed=0;
 
460
      }
 
461
      VOID(tree_insert(&tree, (uchar*) &file_info, 0, tree.custom_arg));
 
462
      if (file_info.used)
 
463
      {
 
464
        if (verbose && !record_pos_file)
 
465
          printf_log("%s: open -> %d",file_info.show_name, file_info.filenr);
 
466
        com_count[command][0]++;
 
467
        if (result)
 
468
          com_count[command][1]++;
 
469
      }
 
470
      break;
 
471
    case MI_LOG_CLOSE:
 
472
      if (verbose && !record_pos_file &&
 
473
          (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
474
        printf_log("%s: %s -> %d",FILENAME(curr_file_info),
 
475
               command_name[command],result);
 
476
      if (curr_file_info)
 
477
      {
 
478
        if (!curr_file_info->closed)
 
479
          files_open--;
 
480
        VOID(tree_delete(&tree, (uchar*) curr_file_info, 0, tree.custom_arg));
 
481
      }
 
482
      break;
 
483
    case MI_LOG_EXTRA:
 
484
      if (my_b_read(&cache,(uchar*) head,1))
 
485
        goto err;
 
486
      extra_command=(enum ha_extra_function) head[0];
 
487
      if (verbose && !record_pos_file &&
 
488
          (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
489
        printf_log("%s: %s(%d) -> %d",FILENAME(curr_file_info),
 
490
                   command_name[command], (int) extra_command,result);
 
491
      if (update && curr_file_info && !curr_file_info->closed)
 
492
      {
 
493
        if (mi_extra(curr_file_info->isam, extra_command, 0) != (int) result)
 
494
        {
 
495
          fflush(stdout);
 
496
          VOID(fprintf(stderr,
 
497
                       "Warning: error %d, expected %d on command %s at %s\n",
 
498
                       my_errno,result,command_name[command],
 
499
                       llstr(isamlog_filepos,llbuff)));
 
500
          fflush(stderr);
 
501
        }
 
502
      }
 
503
      break;
 
504
    case MI_LOG_DELETE:
 
505
      if (my_b_read(&cache,(uchar*) head,8))
 
506
        goto err;
 
507
      filepos=mi_sizekorr(head);
 
508
      if (verbose && (!record_pos_file ||
 
509
                      ((record_pos == filepos || record_pos == NO_FILEPOS) &&
 
510
                       !cmp_filename(curr_file_info,record_pos_file))) &&
 
511
          (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
512
        printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info),
 
513
                   command_name[command],(long) filepos,result);
 
514
      if (update && curr_file_info && !curr_file_info->closed)
 
515
      {
 
516
        if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
 
517
        {
 
518
          if (!recover)
 
519
            goto com_err;
 
520
          if (verbose)
 
521
            printf_log("error: Didn't find row to delete with mi_rrnd");
 
522
          com_count[command][2]++;              /* Mark error */
 
523
        }
 
524
        mi_result=mi_delete(curr_file_info->isam,curr_file_info->record);
 
525
        if ((mi_result == 0 && result) ||
 
526
            (mi_result && (uint) my_errno != result))
 
527
        {
 
528
          if (!recover)
 
529
            goto com_err;
 
530
          if (mi_result)
 
531
            com_count[command][2]++;            /* Mark error */
 
532
          if (verbose)
 
533
            printf_log("error: Got result %d from mi_delete instead of %d",
 
534
                       mi_result, result);
 
535
        }
 
536
      }
 
537
      break;
 
538
    case MI_LOG_WRITE:
 
539
    case MI_LOG_UPDATE:
 
540
      if (my_b_read(&cache,(uchar*) head,12))
 
541
        goto err;
 
542
      filepos=mi_sizekorr(head);
 
543
      length=mi_uint4korr(head+8);
 
544
      buff=0;
 
545
      if (read_string(&cache,&buff,(uint) length))
 
546
        goto err;
 
547
      if ((!record_pos_file ||
 
548
          ((record_pos == filepos || record_pos == NO_FILEPOS) &&
 
549
           !cmp_filename(curr_file_info,record_pos_file))) &&
 
550
          (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
551
      {
 
552
        if (write_file &&
 
553
            (my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP))))
 
554
          goto end;
 
555
        if (verbose)
 
556
          printf_log("%s: %s at %ld, length=%ld -> %d",
 
557
                     FILENAME(curr_file_info),
 
558
                     command_name[command], filepos,length,result);
 
559
      }
 
560
      if (update && curr_file_info && !curr_file_info->closed)
 
561
      {
 
562
        if (curr_file_info->isam->s->base.blobs)
 
563
          fix_blob_pointers(curr_file_info->isam,buff);
 
564
        if ((enum myisam_log_commands) command == MI_LOG_UPDATE)
 
565
        {
 
566
          if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
 
567
          {
 
568
            if (!recover)
 
569
            {
 
570
              result=0;
 
571
              goto com_err;
 
572
            }
 
573
            if (verbose)
 
574
              printf_log("error: Didn't find row to update with mi_rrnd");
 
575
            if (recover == 1 || result ||
 
576
                find_record_with_key(curr_file_info,buff))
 
577
            {
 
578
              com_count[command][2]++;          /* Mark error */
 
579
              break;
 
580
            }
 
581
          }
 
582
          mi_result=mi_update(curr_file_info->isam,curr_file_info->record,
 
583
                              buff);
 
584
          if ((mi_result == 0 && result) ||
 
585
              (mi_result && (uint) my_errno != result))
 
586
          {
 
587
            if (!recover)
 
588
              goto com_err;
 
589
            if (verbose)
 
590
              printf_log("error: Got result %d from mi_update instead of %d",
 
591
                         mi_result, result);
 
592
            if (mi_result)
 
593
              com_count[command][2]++;          /* Mark error */
 
594
          }
 
595
        }
 
596
        else
 
597
        {
 
598
          mi_result=mi_write(curr_file_info->isam,buff);
 
599
          if ((mi_result == 0 && result) ||
 
600
              (mi_result && (uint) my_errno != result))
 
601
          {
 
602
            if (!recover)
 
603
              goto com_err;
 
604
            if (verbose)
 
605
              printf_log("error: Got result %d from mi_write instead of %d",
 
606
                         mi_result, result);
 
607
            if (mi_result)
 
608
              com_count[command][2]++;          /* Mark error */
 
609
          }
 
610
          if (!recover && filepos != curr_file_info->isam->lastpos)
 
611
          {
 
612
            printf("error: Wrote at position: %s, should have been %s",
 
613
                   llstr(curr_file_info->isam->lastpos,llbuff),
 
614
                   llstr(filepos,llbuff2));
 
615
            goto end;
 
616
          }
 
617
        }
 
618
      }
 
619
      my_free(buff,MYF(0));
 
620
      break;
 
621
    case MI_LOG_LOCK:
 
622
      if (my_b_read(&cache,(uchar*) head,sizeof(lock_command)))
 
623
        goto err;
 
624
      memcpy_fixed(&lock_command,head,sizeof(lock_command));
 
625
      if (verbose && !record_pos_file &&
 
626
          (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
627
        printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info),
 
628
                   command_name[command],lock_command,result);
 
629
      if (update && curr_file_info && !curr_file_info->closed)
 
630
      {
 
631
        if (mi_lock_database(curr_file_info->isam,lock_command) !=
 
632
            (int) result)
 
633
          goto com_err;
 
634
      }
 
635
      break;
 
636
    case MI_LOG_DELETE_ALL:
 
637
      if (verbose && !record_pos_file &&
 
638
          (!table_names[0] || (curr_file_info && curr_file_info->used)))
 
639
        printf_log("%s: %s -> %d\n",FILENAME(curr_file_info),
 
640
                   command_name[command],result);
 
641
      break;
 
642
    default:
 
643
      fflush(stdout);
 
644
      VOID(fprintf(stderr,
 
645
                   "Error: found unknown command %d in logfile, aborted\n",
 
646
                   command));
 
647
      fflush(stderr);
 
648
      goto end;
 
649
    }
 
650
  }
 
651
  end_key_cache(dflt_key_cache,1);
 
652
  delete_tree(&tree);
 
653
  VOID(end_io_cache(&cache));
 
654
  VOID(my_close(file,MYF(0)));
 
655
  if (write_file && my_fclose(write_file,MYF(MY_WME)))
 
656
    DBUG_RETURN(1);
 
657
  DBUG_RETURN(0);
 
658
 
 
659
 err:
 
660
  fflush(stdout);
 
661
  VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno));
 
662
  fflush(stderr);
 
663
  goto end;
 
664
 com_err:
 
665
  fflush(stdout);
 
666
  VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %s\n",
 
667
               my_errno,result,command_name[command],
 
668
               llstr(isamlog_filepos,llbuff)));
 
669
  fflush(stderr);
 
670
 end:
 
671
  end_key_cache(dflt_key_cache, 1);
 
672
  delete_tree(&tree);
 
673
  VOID(end_io_cache(&cache));
 
674
  VOID(my_close(file,MYF(0)));
 
675
  if (write_file)
 
676
    VOID(my_fclose(write_file,MYF(MY_WME)));
 
677
  DBUG_RETURN(1);
 
678
}
 
679
 
 
680
 
 
681
static int read_string(IO_CACHE *file, register uchar* *to, register uint length)
 
682
{
 
683
  DBUG_ENTER("read_string");
 
684
 
 
685
  if (*to)
 
686
    my_free((uchar*) *to,MYF(0));
 
687
  if (!(*to= (uchar*) my_malloc(length+1,MYF(MY_WME))) ||
 
688
      my_b_read(file,(uchar*) *to,length))
 
689
  {
 
690
    if (*to)
 
691
      my_free(*to,MYF(0));
 
692
    *to= 0;
 
693
    DBUG_RETURN(1);
 
694
  }
 
695
  *((char*) *to+length)= '\0';
 
696
  DBUG_RETURN (0);
 
697
}                               /* read_string */
 
698
 
 
699
 
 
700
static int file_info_compare(void* cmp_arg __attribute__((unused)),
 
701
                             void *a, void *b)
 
702
{
 
703
  long lint;
 
704
 
 
705
  if ((lint=((struct file_info*) a)->process -
 
706
       ((struct file_info*) b)->process))
 
707
    return lint < 0L ? -1 : 1;
 
708
  return ((struct file_info*) a)->filenr - ((struct file_info*) b)->filenr;
 
709
}
 
710
 
 
711
        /* ARGSUSED */
 
712
 
 
713
static int test_if_open (struct file_info *key,
 
714
                         element_count count __attribute__((unused)),
 
715
                         struct test_if_open_param *param)
 
716
{
 
717
  if (!strcmp(key->name,param->name) && key->id > param->max_id)
 
718
    param->max_id=key->id;
 
719
  return 0;
 
720
}
 
721
 
 
722
 
 
723
static void fix_blob_pointers(MI_INFO *info, uchar *record)
 
724
{
 
725
  uchar *pos;
 
726
  MI_BLOB *blob,*end;
 
727
 
 
728
  pos=record+info->s->base.reclength;
 
729
  for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
 
730
       blob != end ;
 
731
       blob++)
 
732
  {
 
733
    memcpy_fixed(record+blob->offset+blob->pack_length,&pos,sizeof(char*));
 
734
    pos+=_mi_calc_blob_length(blob->pack_length,record+blob->offset);
 
735
  }
 
736
}
 
737
 
 
738
        /* close the file with hasn't been accessed for the longest time */
 
739
        /* ARGSUSED */
 
740
 
 
741
static int test_when_accessed (struct file_info *key,
 
742
                               element_count count __attribute__((unused)),
 
743
                               struct st_access_param *access_param)
 
744
{
 
745
  if (key->accessed < access_param->min_accessed && ! key->closed)
 
746
  {
 
747
    access_param->min_accessed=key->accessed;
 
748
    access_param->found=key;
 
749
  }
 
750
  return 0;
 
751
}
 
752
 
 
753
 
 
754
static void file_info_free(struct file_info *fileinfo)
 
755
{
 
756
  DBUG_ENTER("file_info_free");
 
757
  if (update)
 
758
  {
 
759
    if (!fileinfo->closed)
 
760
      VOID(mi_close(fileinfo->isam));
 
761
    if (fileinfo->record)
 
762
      my_free(fileinfo->record,MYF(0));
 
763
  }
 
764
  my_free(fileinfo->name,MYF(0));
 
765
  my_free(fileinfo->show_name,MYF(0));
 
766
  DBUG_VOID_RETURN;
 
767
}
 
768
 
 
769
 
 
770
 
 
771
static int close_some_file(TREE *tree)
 
772
{
 
773
  struct st_access_param access_param;
 
774
 
 
775
  access_param.min_accessed=LONG_MAX;
 
776
  access_param.found=0;
 
777
 
 
778
  VOID(tree_walk(tree,(tree_walk_action) test_when_accessed,
 
779
                 (void*) &access_param,left_root_right));
 
780
  if (!access_param.found)
 
781
    return 1;                   /* No open file that is possibly to close */
 
782
  if (mi_close(access_param.found->isam))
 
783
    return 1;
 
784
  access_param.found->closed=1;
 
785
  return 0;
 
786
}
 
787
 
 
788
 
 
789
static int reopen_closed_file(TREE *tree, struct file_info *fileinfo)
 
790
{
 
791
  char name[FN_REFLEN];
 
792
  if (close_some_file(tree))
 
793
    return 1;                           /* No file to close */
 
794
  strmov(name,fileinfo->show_name);
 
795
  if (fileinfo->id > 1)
 
796
    *strrchr(name,'<')='\0';            /* Remove "<id>" */
 
797
 
 
798
  if (!(fileinfo->isam= mi_open(name,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
 
799
    return 1;
 
800
  fileinfo->closed=0;
 
801
  re_open_count++;
 
802
  return 0;
 
803
}
 
804
 
 
805
        /* Try to find record with uniq key */
 
806
 
 
807
static int find_record_with_key(struct file_info *file_info, uchar *record)
 
808
{
 
809
  uint key;
 
810
  MI_INFO *info=file_info->isam;
 
811
  uchar tmp_key[MI_MAX_KEY_BUFF];
 
812
 
 
813
  for (key=0 ; key < info->s->base.keys ; key++)
 
814
  {
 
815
    if (mi_is_key_active(info->s->state.key_map, key) &&
 
816
        info->s->keyinfo[key].flag & HA_NOSAME)
 
817
    {
 
818
      VOID(_mi_make_key(info,key,tmp_key,record,0L));
 
819
      return mi_rkey(info,file_info->record,(int) key,tmp_key,0,
 
820
                     HA_READ_KEY_EXACT);
 
821
    }
 
822
  }
 
823
  return 1;
 
824
}
 
825
 
 
826
 
 
827
static void printf_log(const char *format,...)
 
828
{
 
829
  char llbuff[21];
 
830
  va_list args;
 
831
  va_start(args,format);
 
832
  if (verbose > 2)
 
833
    printf("%9s:",llstr(isamlog_filepos,llbuff));
 
834
  if (verbose > 1)
 
835
    printf("%5ld ",isamlog_process);    /* Write process number */
 
836
  (void) vprintf((char*) format,args);
 
837
  putchar('\n');
 
838
  va_end(args);
 
839
}
 
840
 
 
841
 
 
842
static my_bool cmp_filename(struct file_info *file_info, char * name)
 
843
{
 
844
  if (!file_info)
 
845
    return 1;
 
846
  return strcmp(file_info->name,name) ? 1 : 0;
 
847
}
 
848
 
 
849
#include "mi_extrafunc.h"