~drizzle-trunk/drizzle/development

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
/* 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)
51.1.117 by Jay Pipes
DBUG symbol removal
314
    return(1);
1 by brian
clean slate
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));
51.1.117 by Jay Pipes
DBUG symbol removal
321
      return(1);
1 by brian
clean slate
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)))
51.1.117 by Jay Pipes
DBUG symbol removal
650
    return(1);
651
  return(0);
1 by brian
clean slate
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)));
51.1.117 by Jay Pipes
DBUG symbol removal
671
  return(1);
1 by brian
clean slate
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;
51.1.117 by Jay Pipes
DBUG symbol removal
685
    return(1);
1 by brian
clean slate
686
  }
687
  *((char*) *to+length)= '\0';
51.1.117 by Jay Pipes
DBUG symbol removal
688
  return (0);
1 by brian
clean slate
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));
51.1.117 by Jay Pipes
DBUG symbol removal
757
  return;
1 by brian
clean slate
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