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