home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / myisam / myisamlog.c < prev    next >
C/C++ Source or Header  |  2000-09-29  |  24KB  |  882 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or
  6.    (at your option) any later version.
  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.   my_string name,show_name,record;
  37.   MI_INFO *isam;
  38.   bool closed,used;
  39.   ulong accessed;
  40. };
  41.  
  42. struct test_if_open_param {
  43.   my_string 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(my_string file_name,char **table_names);
  58. static int read_string(IO_CACHE *file,gptr *to,uint length);
  59. static int file_info_compare(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,byte *record);
  63. static uint set_maximum_open_files(uint);
  64. static int test_when_accessed(struct file_info *key,element_count count,
  65.                   struct st_access_param *access_param);
  66. static void file_info_free(struct file_info *info);
  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,byte *record);
  70. static void printf_log(const char *str,...);
  71. static bool cmp_filename(struct file_info *file_info,my_string 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,opt_myisam_with_debug=0;
  75. static my_string log_filename=0,filepath=0,write_filename=0,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.  /* Nr of isam-files */
  93.   max_files=(set_maximum_open_files(min(max_files,8))-6)/2;
  94.  
  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_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=" ";                /* Skipp 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 'D':
  205.     opt_myisam_with_debug=1;
  206.     break;
  207.       case 'P':
  208.     opt_processes=1;
  209.     break;
  210.       case 'R':
  211.     if (! *++pos)
  212.     {
  213.       if (!--*argc)
  214.         goto err;
  215.       else
  216.         pos= *(++*argv);
  217.     }
  218.     record_pos_file=(char*) pos;
  219.     if (!--*argc)
  220.       goto err;
  221.     record_pos=(my_off_t) strtoll(*(++*argv),NULL,10);
  222.     pos=" ";
  223.     break;
  224.       case 'v':
  225.     verbose++;
  226.     break;
  227.       case 'w':
  228.     if (! *++pos)
  229.     {
  230.       if (!--*argc)
  231.         goto err;
  232.       else
  233.         pos= *(++*argv);
  234.     }
  235.     write_filename=(char*) pos;
  236.     pos=" ";
  237.     break;
  238.       case 'F':
  239.     if (! *++pos)
  240.     {
  241.       if (!--*argc)
  242.         goto err;
  243.       else
  244.         pos= *(++*argv);
  245.     }
  246.     filepath= (char*) pos;
  247.     pos=" ";
  248.     break;
  249.       case 'V':
  250.     version=1;
  251.     /* Fall through */
  252.       case 'I':
  253.       case '?':
  254.     printf("%s  Ver 1.3 for %s at %s\n",my_progname,SYSTEM_TYPE,
  255.            MACHINE_TYPE);
  256.     puts("By Monty, for your professional use\n");
  257.     if (version)
  258.       break;
  259.     puts("Write info about whats in a myisam log file.");
  260.     printf("If no file name is given %s is used\n",log_filename);
  261.     puts("");
  262.     printf(usage,my_progname);
  263.     puts("");
  264.     puts("Options: -? or -I \"Info\"     -V \"version\"   -c \"do only # commands\"");
  265.     puts("         -f \"max open files\" -F \"filepath\"  -i \"extra info\"");
  266.     puts("         -o \"offset\"         -p # \"remove # components from path\"");
  267.     puts("         -r \"recover\"        -R \"file recordposition\"");
  268.     puts("         -u \"update\"         -v \"verbose\"   -w \"write file\"");
  269.     puts("         -D \"myisam compileled with DBUG\"   -P \"processes\"");
  270.     puts("\nOne can give a second and a third '-v' for more verbose.");
  271.     puts("Normaly one does a update (-u).");
  272.     puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted.");
  273.     puts("If one gives table names as arguments only these tables will be updated\n");
  274.     help=1;
  275.     break;
  276.       default:
  277.     printf("illegal option: \"-%c\"\n",*pos);
  278.     break;
  279.       }
  280.     }
  281.   }
  282.   if (! *argc)
  283.   {
  284.     if (help)
  285.     exit(0);
  286.     (*argv)++;
  287.   }
  288.   if (*argc >= 1)
  289.   {
  290.     log_filename=(char*) pos;
  291.     (*argc)--;
  292.     (*argv)++;
  293.   }
  294.   return;
  295.  err:
  296.   VOID(fprintf(stderr,"option \"%c\" used without or with wrong argument\n",
  297.            option));
  298.   exit(1);
  299. }
  300.  
  301.  
  302. static int examine_log(my_string file_name, char **table_names)
  303. {
  304.   uint command,result,files_open;
  305.   ulong access_time,length;
  306.   my_off_t filepos;
  307.   int lock_command,mi_result;
  308.   char isam_file_name[FN_REFLEN],llbuff[21],llbuff2[21];
  309.   uchar head[20];
  310.   gptr    buff;
  311.   struct test_if_open_param open_param;
  312.   IO_CACHE cache;
  313.   File file;
  314.   FILE *write_file;
  315.   enum ha_extra_function extra_command;
  316.   TREE tree;
  317.   struct file_info file_info,*curr_file_info;
  318.   DBUG_ENTER("examine_log");
  319.  
  320.   if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0)
  321.     DBUG_RETURN(1);
  322.   write_file=0;
  323.   if (write_filename)
  324.   {
  325.     if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME))))
  326.     {
  327.       my_close(file,MYF(0));
  328.       DBUG_RETURN(1);
  329.     }
  330.   }
  331.  
  332.   init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
  333.   bzero((gptr) com_count,sizeof(com_count));
  334.   init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1,
  335.         (void(*)(void*)) file_info_free);
  336.   VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
  337.  
  338.   files_open=0; access_time=0;
  339.   while (access_time++ != number_of_commands &&
  340.      !my_b_read(&cache,(byte*) 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.     {
  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.       {
  380.     printf("\nWarning: %s is opened with same process and filenumber\nMaybe you should use the -P option ?\n",
  381.            curr_file_info->show_name);
  382.       }
  383.       if (my_b_read(&cache,(byte*) 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,(gptr*) &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.     {
  410.       strmov(isam_file_name,filepath);
  411.       convert_dirname(isam_file_name);
  412.       to=strend(isam_file_name);
  413.     }
  414.     strmov(to,pos);
  415.     fn_ext(isam_file_name)[0]=0;    /* Remove extension */
  416.       }
  417.       open_param.name=file_info.name;
  418.       open_param.max_id=0;
  419.       VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param,
  420.              left_root_right));
  421.       file_info.id=open_param.max_id+1;
  422.       file_info.show_name=my_memdup(isam_file_name,
  423.                     (uint) strlen(isam_file_name)+6,
  424.                     MYF(MY_WME));
  425.       if (file_info.id > 1)
  426.     sprintf(strend(file_info.show_name),"<%d>",file_info.id);
  427.       file_info.closed=1;
  428.       file_info.accessed=access_time;
  429.       file_info.used=1;
  430.       if (table_names[0])
  431.       {
  432.     char **name;
  433.     file_info.used=0;
  434.     for (name=table_names ; *name ; name++)
  435.     {
  436.       if (!strcmp(*name,isam_file_name))
  437.         file_info.used=1;            /* Update/log only this */
  438.     }
  439.       }
  440.       if (update && file_info.used)
  441.       {
  442.     if (files_open >= max_files)
  443.     {
  444.       if (close_some_file(&tree))
  445.         goto com_err;
  446.       files_open--;
  447.     }
  448.     if (!(file_info.isam= mi_open(isam_file_name,O_RDWR,
  449.                       HA_OPEN_WAIT_IF_LOCKED)))
  450.       goto com_err;
  451.     if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength,
  452.                      MYF(MY_WME))))
  453.       goto end;
  454.     files_open++;
  455.     file_info.closed=0;
  456.     if (opt_myisam_with_debug)
  457.       file_info.isam->s->rnd= 0;
  458.     else
  459.       file_info.isam->s->rnd= isamlog_process;
  460.       }
  461.       VOID(tree_insert(&tree,(gptr) &file_info,0));
  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,(gptr) curr_file_info));
  481.       }
  482.       break;
  483.     case MI_LOG_EXTRA:
  484.       if (my_b_read(&cache,(byte*) 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,
  494.              (int) extra_command) != (int) result)
  495.     {
  496.       fflush(stdout);
  497.       VOID(fprintf(stderr,
  498.                "Warning: error %d, expected %d on command %s at %s\n",
  499.                my_errno,result,command_name[command],
  500.                llstr(isamlog_filepos,llbuff)));
  501.       fflush(stderr);
  502.     }
  503.       }
  504.       break;
  505.     case MI_LOG_DELETE:
  506.       if (my_b_read(&cache,(byte*) head,8))
  507.     goto err;
  508.       filepos=mi_sizekorr(head);
  509.       if (verbose && (!record_pos_file ||
  510.               ((record_pos == filepos || record_pos == NO_FILEPOS) &&
  511.                !cmp_filename(curr_file_info,record_pos_file))) &&
  512.       (!table_names[0] || (curr_file_info && curr_file_info->used)))
  513.     printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info),
  514.            command_name[command],(long) filepos,result);
  515.       if (update && curr_file_info && !curr_file_info->closed)
  516.       {
  517.     if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
  518.     {
  519.       if (!recover)
  520.         goto com_err;
  521.       if (verbose)
  522.         printf_log("error: Didn't find row to delete with mi_rrnd");
  523.       com_count[command][2]++;        /* Mark error */
  524.     }
  525.     mi_result=mi_delete(curr_file_info->isam,curr_file_info->record);
  526.     if ((mi_result == 0 && result) ||
  527.         (mi_result && (uint) my_errno != result))
  528.     {
  529.       if (!recover)
  530.         goto com_err;
  531.       if (mi_result)
  532.         com_count[command][2]++;        /* Mark error */
  533.       if (verbose)
  534.         printf_log("error: Got result %d from mi_delete instead of %d",
  535.                mi_result, result);
  536.     }
  537.       }
  538.       break;
  539.     case MI_LOG_WRITE:
  540.     case MI_LOG_UPDATE:
  541.       if (my_b_read(&cache,(byte*) head,12))
  542.     goto err;
  543.       filepos=mi_sizekorr(head);
  544.       length=mi_uint4korr(head+8);
  545.       buff=0;
  546.       if (read_string(&cache,&buff,(uint) length))
  547.     goto err;
  548.       if ((!record_pos_file ||
  549.       ((record_pos == filepos || record_pos == NO_FILEPOS) &&
  550.        !cmp_filename(curr_file_info,record_pos_file))) &&
  551.       (!table_names[0] || (curr_file_info && curr_file_info->used)))
  552.       {
  553.     if (write_file &&
  554.         (my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP))))
  555.       goto end;
  556.     if (verbose)
  557.       printf_log("%s: %s at %ld, length=%ld -> %d",
  558.              FILENAME(curr_file_info),
  559.              command_name[command], filepos,length,result);
  560.       }
  561.       if (update && curr_file_info && !curr_file_info->closed)
  562.       {
  563.     if (curr_file_info->isam->s->base.blobs)
  564.       fix_blob_pointers(curr_file_info->isam,buff);
  565.     if ((enum myisam_log_commands) command == MI_LOG_UPDATE)
  566.     {
  567.       if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
  568.       {
  569.         if (!recover)
  570.         {
  571.           result=0;
  572.           goto com_err;
  573.         }
  574.         if (verbose)
  575.           printf_log("error: Didn't find row to update with mi_rrnd");
  576.         if (recover == 1 || result ||
  577.         find_record_with_key(curr_file_info,buff))
  578.         {
  579.           com_count[command][2]++;        /* Mark error */
  580.           break;
  581.         }
  582.       }
  583.       mi_result=mi_update(curr_file_info->isam,curr_file_info->record,
  584.                   buff);
  585.       if ((mi_result == 0 && result) ||
  586.           (mi_result && (uint) my_errno != result))
  587.       {
  588.         if (!recover)
  589.           goto com_err;
  590.         if (verbose)
  591.           printf_log("error: Got result %d from mi_update instead of %d",
  592.              mi_result, result);
  593.         if (mi_result)
  594.           com_count[command][2]++;        /* Mark error */
  595.       }
  596.     }
  597.     else
  598.     {
  599.       mi_result=mi_write(curr_file_info->isam,buff);
  600.       if ((mi_result == 0 && result) ||
  601.           (mi_result && (uint) my_errno != result))
  602.       {
  603.         if (!recover)
  604.           goto com_err;
  605.         if (verbose)
  606.           printf_log("error: Got result %d from mi_write instead of %d",
  607.              mi_result, result);
  608.         if (mi_result)
  609.           com_count[command][2]++;        /* Mark error */
  610.       }
  611.       if (!recover && filepos != curr_file_info->isam->lastpos)
  612.       {
  613.         printf("error: Wrote at position: %s, should have been %s",
  614.            llstr(curr_file_info->isam->lastpos,llbuff),
  615.            llstr(filepos,llbuff2));
  616.         goto end;
  617.       }
  618.     }
  619.       }
  620.       my_free(buff,MYF(0));
  621.       break;
  622.     case MI_LOG_LOCK:
  623.       if (my_b_read(&cache,(byte*) head,sizeof(lock_command)))
  624.     goto err;
  625.       memcpy_fixed(&lock_command,head,sizeof(lock_command));
  626.       if (verbose && !record_pos_file &&
  627.       (!table_names[0] || (curr_file_info && curr_file_info->used)))
  628.     printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info),
  629.            command_name[command],lock_command,result);
  630.       if (update && curr_file_info && !curr_file_info->closed)
  631.       {
  632.     if (mi_lock_database(curr_file_info->isam,lock_command) !=
  633.         (int) result)
  634.       goto com_err;
  635.       }
  636.       break;
  637.     case MI_LOG_DELETE_ALL:
  638.       if (verbose && !record_pos_file &&
  639.       (!table_names[0] || (curr_file_info && curr_file_info->used)))
  640.     printf_log("%s: %s -> %d\n",FILENAME(curr_file_info),
  641.            command_name[command],result);
  642.       break;
  643.     default:
  644.       fflush(stdout);
  645.       VOID(fprintf(stderr,
  646.            "Error: found unknown command %d in logfile, aborted\n",
  647.            command));
  648.       fflush(stderr);
  649.       goto end;
  650.     }
  651.   }
  652.   end_key_cache();
  653.   delete_tree(&tree);
  654.   VOID(end_io_cache(&cache));
  655.   VOID(my_close(file,MYF(0)));
  656.   if (write_file && my_fclose(write_file,MYF(MY_WME)))
  657.     DBUG_RETURN(1);
  658.   DBUG_RETURN(0);
  659.  
  660.  err:
  661.   fflush(stdout);
  662.   VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno));
  663.   fflush(stderr);
  664.   goto end;
  665.  com_err:
  666.   fflush(stdout);
  667.   VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %s\n",
  668.            my_errno,result,command_name[command],
  669.            llstr(isamlog_filepos,llbuff)));
  670.   fflush(stderr);
  671.  end:
  672.   end_key_cache();
  673.   delete_tree(&tree);
  674.   VOID(end_io_cache(&cache));
  675.   VOID(my_close(file,MYF(0)));
  676.   if (write_file)
  677.     VOID(my_fclose(write_file,MYF(MY_WME)));
  678.   DBUG_RETURN(1);
  679. }
  680.  
  681.  
  682. static int read_string(IO_CACHE *file, register gptr *to, register uint length)
  683. {
  684.   DBUG_ENTER("read_string");
  685.  
  686.   if (*to)
  687.     my_free((gptr) *to,MYF(0));
  688.   if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
  689.       my_b_read(file,(byte*) *to,length))
  690.   {
  691.     if (*to)
  692.       my_free(*to,MYF(0));
  693.     *to= 0;
  694.     DBUG_RETURN(1);
  695.   }
  696.   *((char*) *to+length)= '\0';
  697.   DBUG_RETURN (0);
  698. }                /* read_string */
  699.  
  700.  
  701. static int file_info_compare(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, byte *record)
  724. {
  725.   byte *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. static uint set_maximum_open_files(uint maximum_files)
  739. {
  740. #if defined(HAVE_GETRUSAGE) && defined(RLIMIT_NOFILE)
  741.   struct rlimit rlimit;
  742.   int old_max;
  743.  
  744.   if (maximum_files > MY_NFILE)
  745.     maximum_files=MY_NFILE;            /* Don't crash my_open */
  746.  
  747.   if (!getrlimit(RLIMIT_NOFILE,&rlimit))
  748.   {
  749.     old_max=rlimit.rlim_max;
  750.     if (maximum_files && (int) maximum_files > old_max)
  751.       rlimit.rlim_max=maximum_files;
  752.     rlimit.rlim_cur=rlimit.rlim_max;
  753.     if (setrlimit(RLIMIT_NOFILE,&rlimit))
  754.     {
  755.       if (old_max != (int) maximum_files)
  756.       {                        /* Set as much as we can */
  757.     rlimit.rlim_max=rlimit.rlim_cur=old_max;
  758.     setrlimit(RLIMIT_NOFILE,&rlimit);
  759.       }
  760.     }
  761.     getrlimit(RLIMIT_NOFILE,&rlimit);        /* Read if broken setrlimit */
  762.     if (maximum_files && maximum_files < rlimit.rlim_cur)
  763.       VOID(fprintf(stderr,"Warning: Error from setrlimit: Max open files is %d\n",old_max));
  764.     return rlimit.rlim_cur;
  765.   }
  766. #endif
  767.   return min(maximum_files,MY_NFILE);
  768. }
  769.  
  770.     /* close the file with hasn't been accessed for the longest time */
  771.     /* ARGSUSED */
  772.  
  773. static int test_when_accessed (struct file_info *key,
  774.                    element_count count __attribute__((unused)),
  775.                    struct st_access_param *access_param)
  776. {
  777.   if (key->accessed < access_param->min_accessed && ! key->closed)
  778.   {
  779.     access_param->min_accessed=key->accessed;
  780.     access_param->found=key;
  781.   }
  782.   return 0;
  783. }
  784.  
  785.  
  786. static void file_info_free(struct file_info *fileinfo)
  787. {
  788.   DBUG_ENTER("file_info_free");
  789.   if (update)
  790.   {
  791.     if (!fileinfo->closed)
  792.       VOID(mi_close(fileinfo->isam));
  793.     if (fileinfo->record)
  794.       my_free(fileinfo->record,MYF(0));
  795.   }
  796.   my_free(fileinfo->name,MYF(0));
  797.   my_free(fileinfo->show_name,MYF(0));
  798.   DBUG_VOID_RETURN;
  799. }
  800.  
  801.  
  802.  
  803. static int close_some_file(TREE *tree)
  804. {
  805.   struct st_access_param access_param;
  806.  
  807.   access_param.min_accessed=LONG_MAX;
  808.   access_param.found=0;
  809.  
  810.   VOID(tree_walk(tree,(tree_walk_action) test_when_accessed,
  811.          (void*) &access_param,left_root_right));
  812.   if (!access_param.found)
  813.     return 1;            /* No open file that is possibly to close */
  814.   access_param.found->rnd=access_param.found->isam->s->rnd;
  815.   if (mi_close(access_param.found->isam))
  816.     return 1;
  817.   access_param.found->closed=1;
  818.   return 0;
  819. }
  820.  
  821.  
  822. static int reopen_closed_file(TREE *tree, struct file_info *fileinfo)
  823. {
  824.   char name[FN_REFLEN];
  825.   if (close_some_file(tree))
  826.     return 1;                /* No file to close */
  827.   strmov(name,fileinfo->show_name);
  828.   if (fileinfo->id > 1)
  829.     *strrchr(name,'<')='\0';        /* Remove "<id>" */
  830.  
  831.   if (!(fileinfo->isam= mi_open(name,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
  832.     return 1;
  833.   fileinfo->closed=0;
  834.   fileinfo->isam->s->rnd=fileinfo->rnd;
  835.   re_open_count++;
  836.   return 0;
  837. }
  838.  
  839.     /* Try to find record with uniq key */
  840.  
  841. static int find_record_with_key(struct file_info *file_info, byte *record)
  842. {
  843.   uint key;
  844.   MI_INFO *info=file_info->isam;
  845.   uchar tmp_key[MI_MAX_KEY_BUFF];
  846.  
  847.   for (key=0 ; key < info->s->base.keys ; key++)
  848.   {
  849.     if ((((ulonglong) 1 << key) & info->s->state.key_map) &&
  850.     info->s->keyinfo[key].flag & HA_NOSAME)
  851.     {
  852.       VOID(_mi_make_key(info,key,tmp_key,record,0L));
  853.       return mi_rkey(info,file_info->record,(int) key,(char*) tmp_key,0,
  854.              HA_READ_KEY_EXACT);
  855.     }
  856.   }
  857.   return 1;
  858. }
  859.  
  860.  
  861. static void printf_log(const char *format,...)
  862. {
  863.   char llbuff[21];
  864.   va_list args;
  865.   va_start(args,format);
  866.   if (verbose > 2)
  867.     printf("%9s:",llstr(isamlog_filepos,llbuff));
  868.   if (verbose > 1)
  869.     printf("%5ld ",isamlog_process);    /* Write process number */
  870.   (void) vprintf((char*) format,args);
  871.   putchar('\n');
  872.   va_end(args);
  873. }
  874.  
  875.  
  876. static bool cmp_filename(struct file_info *file_info, my_string name)
  877. {
  878.   if (!file_info)
  879.     return 1;
  880.   return strcmp(file_info->name,name) ? 1 : 0;
  881. }
  882.