~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 '#':
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"