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