~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/myisamlog.c

  • Committer: Patrick Galbraith
  • Date: 2008-07-24 16:57:40 UTC
  • mto: (202.2.4 rename-mysql-to-drizzle)
  • mto: This revision was merged to the branch mainline in revision 212.
  • Revision ID: patg@ishvara-20080724165740-x58yw6zs6d9o17lf
Most everything working with client rename
mysqlslap test still fails... can't connect to the server

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