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