pack_isam.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:56k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 1979-1999 TcX AB & Monty Program KB & Detron HB
  2.    This software is distributed with NO WARRANTY OF ANY KIND.  No author or
  3.    distributor accepts any responsibility for the consequences of using it, or
  4.    for whether it serves any particular purpose or works at all, unless he or
  5.    she says so in writing.  Refer to the Free Public License (the "License")
  6.    for full details.
  7.    Every copy of this file must include a copy of the License, normally in a
  8.    plain ASCII text file named PUBLIC. The License grants you the right to
  9.    copy, modify and redistribute this file, but only under certain conditions
  10.    described in the License.  Among other things, the License requires that
  11.    the copyright notice and this notice be preserved on all copies. */
  12. /* Pack isam file*/
  13. #ifndef USE_MY_FUNC
  14. #define USE_MY_FUNC /* We nead at least my_malloc */
  15. #endif
  16. #include "isamdef.h"
  17. #include <queues.h>
  18. #include <my_tree.h>
  19. #include "mysys_err.h"
  20. #ifdef MSDOS
  21. #include <io.h>
  22. #endif
  23. #ifndef __GNU_LIBRARY__
  24. #define __GNU_LIBRARY__ /* Skipp warnings in getopt.h */
  25. #endif
  26. #include <getopt.h>
  27. #if INT_MAX > 32767
  28. #define BITS_SAVED 32
  29. #else
  30. #define BITS_SAVED 16
  31. #endif
  32. #define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
  33. #define HEAD_LENGTH 32
  34. #define ALLOWED_JOIN_DIFF 256 /* Diff allowed to join trees */
  35. #define DATA_TMP_EXT ".TMD"
  36. #define OLD_EXT ".OLD"
  37. #define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
  38. #ifdef __WIN__
  39. static double ulonglong2double(ulonglong value)
  40. {
  41.   longlong nr=(longlong) value;
  42.   if (nr >= 0)
  43.     return (double) nr;
  44.   return (18446744073709551616.0 + (double) nr);
  45. }
  46. #if SIZEOF_OFF_T > 4
  47. #define my_off_t2double(A) ulonglong2double(A)
  48. #else
  49. #define my_off_t2double(A) ((double) (A))
  50. #endif /* SIZEOF_OFF_T > 4 */
  51. #endif
  52. struct st_file_buffer {
  53.   File file;
  54.   char *buffer,*pos,*end;
  55.   my_off_t pos_in_file;
  56.   int bits;
  57.   uint byte;
  58. };
  59. struct st_huff_tree;
  60. struct st_huff_element;
  61. typedef struct st_huff_counts {
  62.   uint field_length,max_zero_fill;
  63.   uint pack_type;
  64.   uint max_end_space,max_pre_space,length_bits,min_space;
  65.   enum en_fieldtype field_type;
  66.   struct st_huff_tree *tree; /* Tree for field */
  67.   my_off_t counts[256];
  68.   my_off_t end_space[8];
  69.   my_off_t pre_space[8];
  70.   my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
  71.   TREE int_tree;
  72.   byte *tree_buff;
  73.   byte *tree_pos;
  74. } HUFF_COUNTS;
  75. typedef struct st_huff_element HUFF_ELEMENT;
  76. struct st_huff_element {
  77.   my_off_t count;
  78.   union un_element {
  79.     struct st_nod {
  80.       HUFF_ELEMENT *left,*right;
  81.     } nod;
  82.     struct st_leaf {
  83.       HUFF_ELEMENT *null;
  84.       uint element_nr; /* Number of element */
  85.     } leaf;
  86.   } a;
  87. };
  88. typedef struct st_huff_tree {
  89.   HUFF_ELEMENT *root,*element_buffer;
  90.   HUFF_COUNTS *counts;
  91.   uint tree_number;
  92.   uint elements;
  93.   my_off_t bytes_packed;
  94.   uint tree_pack_length;
  95.   uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
  96.   ulong *code;
  97.   uchar *code_len;
  98. } HUFF_TREE;
  99. typedef struct st_isam_mrg {
  100.   N_INFO **file,**current,**end;
  101.   uint count;
  102.   uint min_pack_length; /* Theese is used by packed data */
  103.   uint max_pack_length;
  104.   uint ref_length;
  105.   my_off_t records;
  106. } MRG_INFO;
  107. extern int main(int argc,char * *argv);
  108. static void get_options(int *argc,char ***argv);
  109. static N_INFO *open_isam_file(char *name,int mode);
  110. static bool open_isam_files(MRG_INFO *mrg,char **names,uint count);
  111. static int compress(MRG_INFO *file,char *join_name);
  112. static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records);
  113. static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
  114.    uint trees,
  115.    HUFF_COUNTS *huff_counts,
  116.    uint fields);
  117. static int compare_tree(const uchar *s,const uchar *t);
  118. static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
  119. static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
  120.  my_off_t records);
  121. static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
  122.        uint max_space_length,my_off_t *space_counts,
  123.        my_off_t tot_space_count,
  124.        enum en_fieldtype field_type);
  125. static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
  126. static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
  127. static int compare_huff_elements(void *not_used, byte *a,byte *b);
  128. static int save_counts_in_queue(byte *key,element_count count,
  129.     HUFF_TREE *tree);
  130. static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
  131. static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
  132. static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
  133. static void make_traverse_code_tree(HUFF_TREE *huff_tree,
  134.     HUFF_ELEMENT *element,uint size,
  135.     ulong code);
  136. static int write_header(MRG_INFO *isam_file, uint header_length,uint trees,
  137. my_off_t tot_elements,my_off_t filelength);
  138. static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
  139. static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
  140. static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
  141.        HUFF_ELEMENT *element,
  142.        uint *offset);
  143. static uint max_bit(uint value);
  144. static int compress_isam_file(MRG_INFO *file,HUFF_COUNTS *huff_counts);
  145. static char *make_new_name(char *new_name,char *old_name);
  146. static char *make_old_name(char *new_name,char *old_name);
  147. static void init_file_buffer(File file,pbool read_buffer);
  148. static int flush_buffer(uint neaded_length);
  149. static void end_file_buffer(void);
  150. static void write_bits(ulong value,uint bits);
  151. static void flush_bits(void);
  152. static void save_integer(byte *pos,uint pack_length,my_off_t value);
  153. static void save_state(N_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
  154.        ulong crc);
  155. static int save_state_mrg(File file,MRG_INFO *isam_file,my_off_t new_length,
  156.   ulong crc);
  157. static int mrg_close(MRG_INFO *mrg);
  158. static int mrg_rrnd(MRG_INFO *info,byte *buf);
  159. static void mrg_reset(MRG_INFO *mrg);
  160. static int backup=0,error_on_write=0,test_only=0,verbose=0,silent=0,
  161.    write_loop=0,force_pack=0,opt_wait=0,isamchk_neaded=0;
  162. static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
  163. static uint tree_buff_length=8196-MALLOC_OVERHEAD,force_pack_ref_length;
  164. static char tmp_dir[FN_REFLEN]={0},*join_table;
  165. static my_off_t intervall_length;
  166. static ulong  crc;
  167. static struct st_file_buffer file_buffer;
  168. static QUEUE queue;
  169. static HUFF_COUNTS *global_count;
  170. static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  171. static const char *load_default_groups[]= { "pack_isam",0 };
  172. /* The main program */
  173. int main(int argc, char **argv)
  174. {
  175.   int error,ok;
  176.   MRG_INFO merge;
  177.   MY_INIT(argv[0]);
  178.   load_defaults("my",load_default_groups,&argc,&argv);
  179.   get_options(&argc,&argv);
  180.   error=ok=isamchk_neaded=0;
  181.   if (join_table)
  182.   { /* Join files into one */
  183.     if (open_isam_files(&merge,argv,(uint) argc) ||
  184. compress(&merge,join_table))
  185.       error=1;
  186.   }
  187.   else while (argc--)
  188.   {
  189.     N_INFO *isam_file;
  190.     if (!(isam_file=open_isam_file(*argv++,O_RDWR)))
  191.       error=1;
  192.     else
  193.     {
  194.       merge.file= &isam_file;
  195.       merge.current=0;
  196.       merge.count=1;
  197.       if (compress(&merge,0))
  198. error=1;
  199.       else
  200. ok=1;
  201.     }
  202.   }
  203.   if (ok && isamchk_neaded && !silent)
  204.     puts("Remember to run isamchk -rq on compressed databases");
  205.   VOID(fflush(stdout)); VOID(fflush(stderr));
  206.   my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
  207.   exit(error ? 2 : 0);
  208. #ifndef _lint
  209.   return 0; /* No compiler warning */
  210. #endif
  211. }
  212. static struct option long_options[] =
  213. {
  214.   {"backup", no_argument,    0, 'b'},
  215.   {"debug", optional_argument, 0, '#'},
  216.   {"force", no_argument,    0, 'f'},
  217.   {"join", required_argument, 0, 'j'},
  218.   {"help", no_argument,    0, '?'},
  219.   {"packlength",required_argument, 0, 'p'},
  220.   {"silent", no_argument,    0, 's'},
  221.   {"tmpdir", required_argument, 0, 'T'},
  222.   {"test", no_argument,    0, 't'},
  223.   {"verbose", no_argument,    0, 'v'},
  224.   {"version", no_argument,    0, 'V'},
  225.   {"wait", no_argument,    0, 'w'},
  226.   {0, 0, 0, 0}
  227. };
  228. static void print_version(void)
  229. {
  230.   printf("%s  Ver 5.8 for %s on %sn",my_progname,SYSTEM_TYPE,MACHINE_TYPE);
  231. }
  232. static void usage(void)
  233. {
  234.   print_version();
  235.   puts("Copyright (C) 1994-2000 TcX AB & Monty Program KB & Detron HB.");
  236.   puts("This is not free software. You must have a licence to use this program");
  237.   puts("This software comes with ABSOLUTELY NO WARRANTYn");
  238.   puts("Pack a ISAM-table to take much smaller space");
  239.   puts("Keys are not updated, so you must run isamchk -rq on any table");
  240.   puts("that has keys after you have compressed it");
  241.   puts("You should give the .ISM file as the filename argument");
  242.   printf("nUsage: %s [OPTIONS] filename...n", my_progname);
  243.   puts("n
  244.   -b, --backup Make a backup of the table as table_name.OLDn
  245.   -f, --force Force packing of table even if it's gets bigger orn
  246. tempfile exists.n
  247.   -j, --join='new_table_name'n
  248. Join all given tables into 'new_table_name'.n
  249. All tables MUST have the identical layout.n
  250.   -p, --packlength=#    Force storage size of recordlength (1,2 or 3)n
  251.   -s, --silent Be more silent.n
  252.   -t, --test Don't pack table, only test packing itn
  253.   -v, --verbose Write info about progress and packing resultn
  254.   -w, --wait Wait and retry if table is in usen
  255.   -T, --tmpdir=# Use temporary directory to store temporary tablen
  256.   -#, --debug=...       output debug log. Often this is 'd:t:o,filename`n
  257.   -?, --help display this help and exitn
  258.   -V, --version output version information and exitn");
  259.   print_defaults("my",load_default_groups);
  260. };
  261. /* reads options */
  262. /* Initiates DEBUG - but no debugging here ! */
  263. static void get_options(int *argc,char ***argv)
  264. {
  265.   int c,option_index=0;
  266.   uint length;
  267.   my_progname= argv[0][0];
  268.   if (isatty(fileno(stdout)))
  269.     write_loop=1;
  270.   while ((c=getopt_long(*argc,*argv,"bfj:p:stvwT:#::?V",long_options,
  271. &option_index)) != EOF)
  272.   {
  273.     switch(c) {
  274.     case 'b':
  275.       backup=1;
  276.       break;
  277.     case 'f':
  278.       force_pack=1;
  279.       tmpfile_createflag=O_RDWR | O_TRUNC;
  280.       break;
  281.     case 'j':
  282.       join_table=optarg;
  283.       break;
  284.     case 'p':
  285.       force_pack_ref_length=(uint) atoi(optarg);
  286.       if (force_pack_ref_length > 3)
  287. force_pack_ref_length=0;
  288.       break;
  289.     case 's':
  290.       write_loop=verbose=0; silent=1;
  291.       break;
  292.     case 't':
  293.       test_only=verbose=1;
  294.       break;
  295.     case 'T':
  296.       length=(uint) (strmov(tmp_dir,optarg)-tmp_dir);
  297.       if (length != dirname_length(tmp_dir))
  298.       {
  299. tmp_dir[length]=FN_LIBCHAR;
  300. tmp_dir[length+1]=0;
  301.       }
  302.       break;
  303.     case 'v':
  304.       verbose=1; silent=0;
  305.       break;
  306.     case 'w':
  307.       opt_wait=1;
  308.       break;
  309.     case '#':
  310.       DBUG_PUSH(optarg ? optarg : "d:t:o");
  311.       break;
  312.     case 'V': print_version(); exit(0);
  313.     case 'I':
  314.     case '?':
  315.       usage();
  316.       exit(0);
  317.     default:
  318.       fprintf(stderr,"%s: Illegal option: -%cn",my_progname,opterr);
  319.       usage();
  320.       exit(1);
  321.     }
  322.   }
  323.   (*argc)-=optind;
  324.   (*argv)+=optind;
  325.   if (!*argc)
  326.   {
  327.     usage();
  328.     exit(1);
  329.   }
  330.   if (join_table)
  331.   {
  332.     backup=0; /* Not needed */
  333.     tmp_dir[0]=0;
  334.   }
  335.   return;
  336. }
  337. static N_INFO *open_isam_file(char *name,int mode)
  338. {
  339.   N_INFO *isam_file;
  340.   ISAM_SHARE *share;
  341.   DBUG_ENTER("open_isam_file");
  342.   if (!(isam_file=nisam_open(name,mode,(opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
  343.      HA_OPEN_ABORT_IF_LOCKED))))
  344.   {
  345.     VOID(fprintf(stderr,"%s gave error %d on openn",name,my_errno));
  346.     DBUG_RETURN(0);
  347.   }
  348.   share=isam_file->s;
  349.   if (share->base.blobs)
  350.   {
  351.     VOID(fprintf(stderr,"%s has blobs, can't pack itn",name));
  352.     VOID(nisam_close(isam_file));
  353.     DBUG_RETURN(0);
  354.   }
  355.   if (share->base.options & HA_OPTION_COMPRESS_RECORD && !join_table)
  356.   {
  357.     if (!force_pack)
  358.     {
  359.       VOID(fprintf(stderr,"%s is already compressedn",name));
  360.       VOID(nisam_close(isam_file));
  361.       DBUG_RETURN(0);
  362.     }
  363.     if (verbose)
  364.       puts("Recompressing already compressed table");
  365.     share->base.options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
  366.   }
  367.   if (! force_pack && share->state.records != 0 &&
  368.       (share->state.records <= 1 ||
  369.        share->state.data_file_length < 1024) && ! join_table)
  370.   {
  371.     VOID(fprintf(stderr,"%s is too small to compressn",name));
  372.     VOID(nisam_close(isam_file));
  373.     DBUG_RETURN(0);
  374.   }
  375.   VOID(nisam_lock_database(isam_file,F_WRLCK));
  376.   DBUG_RETURN(isam_file);
  377. }
  378. static bool open_isam_files(MRG_INFO *mrg,char **names,uint count)
  379. {
  380.   uint i,j;
  381.   mrg->count=0;
  382.   mrg->current=0;
  383.   mrg->file=(N_INFO**) my_malloc(sizeof(N_INFO*)*count,MYF(MY_FAE));
  384.   for (i=0; i < count ; i++)
  385.   {
  386.     if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY)))
  387.       goto error;
  388.   }
  389.   /* Check that files are identical */
  390.   for (j=0 ; j < count-1 ; j++)
  391.   {
  392.     N_RECINFO *m1,*m2,*end;
  393.     if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
  394. mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
  395.       goto diff_file;
  396.     m1=mrg->file[j]->s->rec;
  397.     end=m1+mrg->file[j]->s->base.fields;
  398.     m2=mrg->file[j+1]->s->rec;
  399.     for ( ; m1 != end ; m1++,m2++)
  400.     {
  401.       if ((m1->base.type != m2->base.type && ! force_pack) ||
  402.   m1->base.length != m2->base.length)
  403. goto diff_file;
  404.     }
  405.   }
  406.   mrg->count=count;
  407.   return 0;
  408.  diff_file:
  409.   fprintf(stderr,"%s: Tables '%s' and '%s' are not identicaln",
  410.   my_progname,names[j],names[j+1]);
  411.  error:
  412.   while (i--)
  413.     nisam_close(mrg->file[i]);
  414.   return 1;
  415. }
  416. static int compress(MRG_INFO *mrg,char *result_table)
  417. {
  418.   int error;
  419.   File new_file,join_isam_file;
  420.   N_INFO *isam_file;
  421.   ISAM_SHARE *share;
  422.   char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
  423.   uint i,header_length,fields,trees,used_trees;
  424.   my_off_t old_length,new_length,tot_elements;
  425.   HUFF_COUNTS *huff_counts;
  426.   HUFF_TREE *huff_trees;
  427.   DBUG_ENTER("compress");
  428.   isam_file=mrg->file[0]; /* Take this as an example */
  429.   share=isam_file->s;
  430.   new_file=join_isam_file= -1;
  431.   trees=fields=0;
  432.   huff_trees=0;
  433.   huff_counts=0;
  434.   /* Create temporary or join file */
  435.   if (backup)
  436.     VOID(fn_format(org_name,isam_file->filename,"",N_NAME_DEXT,2));
  437.   else
  438.     VOID(fn_format(org_name,isam_file->filename,"",N_NAME_DEXT,2+4+16));
  439.   if (!test_only && result_table)
  440.   {
  441.     /* Make a new indexfile based on first file in list */
  442.     uint length;
  443.     char *buff;
  444.     strmov(org_name,result_table); /* Fix error messages */
  445.     VOID(fn_format(new_name,result_table,"",N_NAME_IEXT,2));
  446.     if ((join_isam_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
  447. < 0)
  448.       goto err;
  449.     length=share->base.keystart;
  450.     if (!(buff=my_malloc(length,MYF(MY_WME))))
  451.       goto err;
  452.     if (my_pread(share->kfile,buff,length,0L,MYF(MY_WME | MY_NABP)) ||
  453. my_write(join_isam_file,buff,length,
  454.  MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
  455.     {
  456.       my_free(buff,MYF(0));
  457.       goto err;
  458.     }
  459.     my_free(buff,MYF(0));
  460.     VOID(fn_format(new_name,result_table,"",N_NAME_DEXT,2));
  461.   }
  462.   else if (!tmp_dir[0])
  463.     VOID(make_new_name(new_name,org_name));
  464.   else
  465.     VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
  466.   if (!test_only &&
  467.       (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
  468.     goto err;
  469.   /* Start calculating statistics */
  470.   mrg->records=0;
  471.   for (i=0 ; i < mrg->count ; i++)
  472.     mrg->records+=mrg->file[i]->s->state.records;
  473.   if (write_loop || verbose)
  474.   {
  475.     printf("Compressing %s: (%lu records)n",
  476.    result_table ? new_name : org_name,(ulong) mrg->records);
  477.   }
  478.   trees=fields=share->base.fields;
  479.   huff_counts=init_huff_count(isam_file,mrg->records);
  480.   QUICK_SAFEMALLOC;
  481.   if (write_loop || verbose)
  482.     printf("- Calculating statisticsn");
  483.   if (get_statistic(mrg,huff_counts))
  484.     goto err;
  485.   NORMAL_SAFEMALLOC;
  486.   old_length=0;
  487.   for (i=0; i < mrg->count ; i++)
  488.     old_length+= (mrg->file[i]->s->state.data_file_length -
  489.   mrg->file[i]->s->state.empty);
  490.   if (init_queue(&queue,256,0,0,compare_huff_elements,0))
  491.     goto err;
  492.   check_counts(huff_counts,fields,mrg->records);
  493.   huff_trees=make_huff_trees(huff_counts,trees);
  494.   if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
  495.     goto err;
  496.   if (make_huff_decode_table(huff_trees,fields))
  497.     goto err;
  498.   init_file_buffer(new_file,0);
  499.   file_buffer.pos_in_file=HEAD_LENGTH;
  500.   if (! test_only)
  501.     VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
  502.   write_field_info(huff_counts,fields,used_trees);
  503.   if (!(tot_elements=write_huff_tree(huff_trees,trees)))
  504.     goto err;
  505.   header_length=(uint) file_buffer.pos_in_file+
  506.     (uint) (file_buffer.pos-file_buffer.buffer);
  507.   /* Compress file */
  508.   if (write_loop || verbose)
  509.     printf("- Compressing filen");
  510.   error=compress_isam_file(mrg,huff_counts);
  511.   new_length=file_buffer.pos_in_file;
  512.   if (!error && !test_only)
  513.   {
  514.     char buff[MEMMAP_EXTRA_MARGIN]; /* End marginal for memmap */
  515.     bzero(buff,sizeof(buff));
  516.     error=my_write(file_buffer.file,buff,sizeof(buff),
  517.    MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
  518.   }
  519.   if (!error)
  520.     error=write_header(mrg,header_length,used_trees,tot_elements,
  521.        new_length);
  522.   end_file_buffer();
  523.   if (verbose && mrg->records)
  524.     printf("Min record length: %6d   Max length: %6d   Mean total length: %6lun",
  525.    mrg->min_pack_length,mrg->max_pack_length,
  526.    (ulong) (new_length/mrg->records));
  527.   if (!test_only)
  528.   {
  529.     error|=my_close(new_file,MYF(MY_WME));
  530.     if (!result_table)
  531.     {
  532.       error|=my_close(isam_file->dfile,MYF(MY_WME));
  533.       isam_file->dfile= -1; /* Tell nisam_close file is closed */
  534.     }
  535.   }
  536.   free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
  537.   if (! test_only && ! error)
  538.   {
  539.     if (result_table)
  540.     {
  541.       error=save_state_mrg(join_isam_file,mrg,new_length,crc);
  542.     }
  543.     else
  544.     {
  545.       if (backup)
  546.       {
  547. if (my_rename(org_name,make_old_name(temp_name,isam_file->filename),
  548.       MYF(MY_WME)))
  549.   error=1;
  550. else
  551. {
  552.   if (tmp_dir[0])
  553.   {
  554.     if (!(error=my_copy(new_name,org_name,MYF(MY_WME))))
  555.       VOID(my_delete(new_name,MYF(MY_WME)));
  556.   }
  557.   else
  558.     error=my_rename(new_name,org_name,MYF(MY_WME));
  559.   if (!error)
  560.     VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
  561. }
  562.       }
  563.       else
  564.       {
  565. if (tmp_dir[0])
  566. {
  567.   if (!(error=my_copy(new_name,org_name,
  568.       MYF(MY_WME | MY_HOLD_ORIGINAL_MODES
  569.   | MY_COPYTIME))))
  570.     VOID(my_delete(new_name,MYF(MY_WME)));
  571. }
  572. else
  573.   error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
  574.       }
  575.       if (! error)
  576. save_state(isam_file,mrg,new_length,crc);
  577.     }
  578.   }
  579.   error|=mrg_close(mrg);
  580.   if (join_isam_file >= 0)
  581.     error|=my_close(join_isam_file,MYF(MY_WME));
  582.   if (error)
  583.   {
  584.     VOID(fprintf(stderr,"Aborting: %s is not compressedn",org_name));
  585.     DBUG_RETURN(-1);
  586.   }
  587.   if (write_loop || verbose)
  588.   {
  589.     if (old_length)
  590.       printf("%.4g%%     n",
  591.      my_off_t2double(old_length-new_length)*100.0/
  592.      my_off_t2double(old_length));
  593.     else
  594.       puts("Empty file saved in compressed format");
  595.   }
  596.   DBUG_RETURN(0);
  597.  err:
  598.   free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
  599.   if (new_file >= 0)
  600.     VOID(my_close(new_file,MYF(0)));
  601.   if (join_isam_file >= 0)
  602.     VOID(my_close(join_isam_file,MYF(0)));
  603.   mrg_close(mrg);
  604.   VOID(fprintf(stderr,"Aborted: %s is not compressedn",org_name));
  605.   DBUG_RETURN(-1);
  606. }
  607. /* Init a huff_count-struct for each field and init it */
  608. static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records)
  609. {
  610.   reg2 uint i;
  611.   reg1 HUFF_COUNTS *count;
  612.   if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*sizeof(HUFF_COUNTS),
  613. MYF(MY_ZEROFILL | MY_WME))))
  614.   {
  615.     for (i=0 ; i < info->s->base.fields ; i++)
  616.     {
  617.       enum en_fieldtype type;
  618.       count[i].field_length=info->s->rec[i].base.length;
  619.       type= count[i].field_type= (enum en_fieldtype) info->s->rec[i].base.type;
  620.       if (type == FIELD_INTERVALL ||
  621.   type == FIELD_CONSTANT ||
  622.   type == FIELD_ZERO)
  623. type = FIELD_NORMAL;
  624.       if (count[i].field_length <= 8 &&
  625.   (type == FIELD_NORMAL ||
  626.    type == FIELD_SKIPP_ZERO))
  627. count[i].max_zero_fill= count[i].field_length;
  628.       init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL);
  629.       if (records)
  630. count[i].tree_pos=count[i].tree_buff =
  631.   my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
  632.     MYF(MY_WME));
  633.     }
  634.   }
  635.   return count;
  636. }
  637. /* Free memory used by counts and trees */
  638. static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees, HUFF_COUNTS *huff_counts, uint fields)
  639. {
  640.   register uint i;
  641.   if (huff_trees)
  642.   {
  643.     for (i=0 ; i < trees ; i++)
  644.     {
  645.       if (huff_trees[i].element_buffer)
  646. my_free((gptr) huff_trees[i].element_buffer,MYF(0));
  647.       if (huff_trees[i].code)
  648. my_free((gptr) huff_trees[i].code,MYF(0));
  649.     }
  650.     my_free((gptr) huff_trees,MYF(0));
  651.   }
  652.   if (huff_counts)
  653.   {
  654.     for (i=0 ; i < fields ; i++)
  655.     {
  656.       if (huff_counts[i].tree_buff)
  657.       {
  658. my_free((gptr) huff_counts[i].tree_buff,MYF(0));
  659. delete_tree(&huff_counts[i].int_tree);
  660.       }
  661.     }
  662.     my_free((gptr) huff_counts,MYF(0));
  663.   }
  664.   delete_queue(&queue); /* This is safe to free */
  665.   return;
  666. }
  667. /* Read through old file and gather some statistics */
  668. static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
  669. {
  670.   int error;
  671.   uint length,reclength;
  672.   byte *record,*pos,*next_pos,*end_pos,*start_pos;
  673.   my_off_t record_count;
  674.   HUFF_COUNTS *count,*end_count;
  675.   TREE_ELEMENT *element;
  676.   DBUG_ENTER("get_statistic");
  677.   reclength=mrg->file[0]->s->base.reclength;
  678.   record=(byte*) my_alloca(reclength);
  679.   end_count=huff_counts+mrg->file[0]->s->base.fields;
  680.   record_count=crc=0;
  681.   mrg_reset(mrg);
  682.   while ((error=mrg_rrnd(mrg,record)) >= 0)
  683.   {
  684.     if (! error)
  685.     {
  686.       crc^=checksum(record,reclength);
  687.       for (pos=record,count=huff_counts ;
  688.    count < end_count ;
  689.    count++,
  690.    pos=next_pos)
  691.       {
  692. next_pos=end_pos=(start_pos=pos)+count->field_length;
  693. /* Put value in tree if there is room for it */
  694. if (count->tree_buff)
  695. {
  696.   global_count=count;
  697.   if (!(element=tree_insert(&count->int_tree,pos,0)) ||
  698.       ((element->count == 1 &&
  699.        count->tree_buff + tree_buff_length <
  700.        count->tree_pos + count->field_length) ||
  701.        (count->field_length == 1 &&
  702. count->int_tree.elements_in_tree > 1)))
  703.   {
  704.     delete_tree(&count->int_tree);
  705.     my_free(count->tree_buff,MYF(0));
  706.     count->tree_buff=0;
  707.   }
  708.   else
  709.   {
  710.     if (element->count == 1)
  711.     { /* New element */
  712.       memcpy(count->tree_pos,pos,(size_t) count->field_length);
  713.       tree_set_pointer(element,count->tree_pos);
  714.       count->tree_pos+=count->field_length;
  715.     }
  716.   }
  717. }
  718. /* Save character counters and space-counts and zero-field-counts */
  719. if (count->field_type == FIELD_NORMAL ||
  720.     count->field_type == FIELD_SKIPP_ENDSPACE)
  721. {
  722.   for ( ; end_pos > pos ; end_pos--)
  723.     if (end_pos[-1] != ' ')
  724.       break;
  725.   if (end_pos == pos)
  726.   {
  727.     count->empty_fields++;
  728.     count->max_zero_fill=0;
  729.     continue;
  730.   }
  731.   length= (uint) (next_pos-end_pos);
  732.   count->tot_end_space+=length;
  733.   if (length < 8)
  734.     count->end_space[length]++;
  735.   if (count->max_end_space < length)
  736.     count->max_end_space = length;
  737. }
  738. if (count->field_type == FIELD_NORMAL ||
  739.     count->field_type == FIELD_SKIPP_PRESPACE)
  740. {
  741.   for (pos=start_pos; pos < end_pos ; pos++)
  742.     if (pos[0] != ' ')
  743.       break;
  744.   if (end_pos == pos)
  745.   {
  746.     count->empty_fields++;
  747.     count->max_zero_fill=0;
  748.     continue;
  749.   }
  750.   length= (uint) (pos-start_pos);
  751.   count->tot_pre_space+=length;
  752.   if (length < 8)
  753.     count->pre_space[length]++;
  754.   if (count->max_pre_space < length)
  755.     count->max_pre_space = length;
  756. }
  757. if (count->field_length <= 8 &&
  758.     (count->field_type == FIELD_NORMAL ||
  759.      count->field_type == FIELD_SKIPP_ZERO))
  760. {
  761.   uint i;
  762.   if (!memcmp((byte*) start_pos,zero_string,count->field_length))
  763.   {
  764.     count->zero_fields++;
  765.     continue;
  766.   }
  767. #ifdef BYTE_ORDER_HIGH_FIRST
  768.   for (i =0 ; i < count->max_zero_fill && ! start_pos[i] ; i++) ;
  769.   if (i < count->max_zero_fill)
  770.     count->max_zero_fill=i;
  771. #else
  772.   for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ; i++) ;
  773.   if (i < count->max_zero_fill)
  774.     count->max_zero_fill=i;
  775. #endif
  776. }
  777. for (pos=start_pos ; pos < end_pos ; pos++)
  778.   count->counts[(uchar) *pos]++;
  779.       }
  780.       record_count++;
  781.       if (write_loop && record_count % WRITE_COUNT == 0)
  782.       {
  783. printf("%lur",(ulong) record_count); VOID(fflush(stdout));
  784.       }
  785.     }
  786.   }
  787.   if (write_loop)
  788.   {
  789.     printf("            r"); VOID(fflush(stdout));
  790.   }
  791.   mrg->records=record_count;
  792.   my_afree((gptr) record);
  793.   DBUG_RETURN(0);
  794. }
  795. static int compare_huff_elements(void *not_used __attribute__((unused)),
  796.  byte *a, byte *b)
  797. {
  798.   return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
  799.     (*((my_off_t*) a) == *((my_off_t*) b)  ? 0 : 1);
  800. }
  801. /* Check each tree if we should use pre-space-compress, end-space-
  802.    compress, empty-field-compress or zero-field-compress */
  803. static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
  804. {
  805.   uint space_fields,fill_zero_fields,field_count[(int) FIELD_ZERO+1];
  806.   my_off_t old_length,new_length,length;
  807.   DBUG_ENTER("check_counts");
  808.   bzero((gptr) field_count,sizeof(field_count));
  809.   space_fields=fill_zero_fields=0;
  810.   for (; trees-- ; huff_counts++)
  811.   {
  812.     huff_counts->field_type=FIELD_NORMAL;
  813.     huff_counts->pack_type=0;
  814.     if (huff_counts->zero_fields || ! records)
  815.     {
  816.       my_off_t old_space_count;
  817.       if (huff_counts->zero_fields == records)
  818.       {
  819. huff_counts->field_type= FIELD_ZERO;
  820. huff_counts->bytes_packed=0;
  821. huff_counts->counts[0]=0;
  822. goto found_pack;
  823.       }
  824.       old_space_count=huff_counts->counts[' '];
  825.       huff_counts->counts[' ']+=huff_counts->tot_end_space+
  826. huff_counts->tot_pre_space +
  827.   huff_counts->empty_fields * huff_counts->field_length;
  828.       old_length=calc_packed_length(huff_counts,0)+records/8;
  829.       length=huff_counts->zero_fields*huff_counts->field_length;
  830.       huff_counts->counts[0]+=length;
  831.       new_length=calc_packed_length(huff_counts,0);
  832.       if (old_length < new_length && huff_counts->field_length > 1)
  833.       {
  834. huff_counts->field_type=FIELD_SKIPP_ZERO;
  835. huff_counts->counts[0]-=length;
  836. huff_counts->bytes_packed=old_length- records/8;
  837. goto found_pack;
  838.       }
  839.       huff_counts->counts[' ']=old_space_count;
  840.     }
  841.     huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
  842.     if (huff_counts->empty_fields)
  843.     {
  844.       if (huff_counts->field_length > 2 &&
  845.   huff_counts->empty_fields + (records - huff_counts->empty_fields)*
  846.   (1+max_bit(max(huff_counts->max_pre_space,
  847.  huff_counts->max_end_space))) <
  848.   records * max_bit(huff_counts->field_length))
  849.       {
  850. huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
  851.       }
  852.       else
  853.       {
  854. length=huff_counts->empty_fields*huff_counts->field_length;
  855. if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
  856. {
  857.   huff_counts->tot_end_space+=length;
  858.   huff_counts->max_end_space=huff_counts->field_length;
  859.   if (huff_counts->field_length < 8)
  860.     huff_counts->end_space[huff_counts->field_length]+=
  861.       huff_counts->empty_fields;
  862. }
  863. else
  864. {
  865.   huff_counts->tot_pre_space+=length;
  866.   huff_counts->max_pre_space=huff_counts->field_length;
  867.   if (huff_counts->field_length < 8)
  868.     huff_counts->pre_space[huff_counts->field_length]+=
  869.       huff_counts->empty_fields;
  870. }
  871.       }
  872.     }
  873.     if (huff_counts->tot_end_space)
  874.     {
  875.       huff_counts->counts[' ']+=huff_counts->tot_pre_space;
  876.       if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
  877.       huff_counts->end_space,
  878.       huff_counts->tot_end_space,FIELD_SKIPP_ENDSPACE))
  879. goto found_pack;
  880.       huff_counts->counts[' ']-=huff_counts->tot_pre_space;
  881.     }
  882.     if (huff_counts->tot_pre_space)
  883.     {
  884.       if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
  885.       huff_counts->pre_space,
  886.       huff_counts->tot_pre_space,FIELD_SKIPP_PRESPACE))
  887. goto found_pack;
  888.     }
  889.   found_pack: /* Found field-packing */
  890.     /* Test if we can use zero-fill */
  891.     if (huff_counts->max_zero_fill &&
  892. (huff_counts->field_type == FIELD_NORMAL ||
  893.  huff_counts->field_type == FIELD_SKIPP_ZERO))
  894.     {
  895.       huff_counts->counts[0]-=huff_counts->max_zero_fill*
  896. (huff_counts->field_type == FIELD_SKIPP_ZERO ?
  897.  records - huff_counts->zero_fields : records);
  898.       huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
  899.       huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
  900.     }
  901.     /* Test if intervall-field is better */
  902.     if (huff_counts->tree_buff)
  903.     {
  904.       HUFF_TREE tree;
  905.       tree.element_buffer=0;
  906.       if (!make_huff_tree(&tree,huff_counts) &&
  907.   tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
  908.       {
  909. if (tree.elements == 1)
  910.   huff_counts->field_type=FIELD_CONSTANT;
  911. else
  912.   huff_counts->field_type=FIELD_INTERVALL;
  913. huff_counts->pack_type=0;
  914.       }
  915.       else
  916.       {
  917. my_free((gptr) huff_counts->tree_buff,MYF(0));
  918. delete_tree(&huff_counts->int_tree);
  919. huff_counts->tree_buff=0;
  920.       }
  921.       if (tree.element_buffer)
  922. my_free((gptr) tree.element_buffer,MYF(0));
  923.     }
  924.     if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
  925.       space_fields++;
  926.     if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
  927.       fill_zero_fields++;
  928.     field_count[huff_counts->field_type]++;
  929.   }
  930.   if (verbose)
  931.     printf("nnormal:    %3d  empty-space:     %3d  empty-zero:       %3d  empty-fill: %3dnpre-space: %3d  end-space:       %3d  table-lookup:     %3d  zero:       %3dn",
  932.    field_count[FIELD_NORMAL],space_fields,
  933.    field_count[FIELD_SKIPP_ZERO],fill_zero_fields,
  934.    field_count[FIELD_SKIPP_PRESPACE],
  935.    field_count[FIELD_SKIPP_ENDSPACE],
  936.    field_count[FIELD_INTERVALL],
  937.    field_count[FIELD_ZERO]);
  938.   DBUG_VOID_RETURN;
  939. }
  940. /* Test if we can use space-compression and empty-field-compression */
  941. static int
  942. test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
  943.     uint max_space_length, my_off_t *space_counts,
  944.     my_off_t tot_space_count, enum en_fieldtype field_type)
  945. {
  946.   int min_pos;
  947.   uint length_bits,i;
  948.   my_off_t space_count,min_space_count,min_pack,new_length,skipp;
  949.   length_bits=max_bit(max_space_length);
  950. /* Default no end_space-packing */
  951.   space_count=huff_counts->counts[(uint) ' '];
  952.   min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
  953.   min_pack=calc_packed_length(huff_counts,0);
  954.   min_pos= -2;
  955.   huff_counts->counts[(uint) ' ']=space_count;
  956. /* Test with allways space-count */
  957.   new_length=huff_counts->bytes_packed+length_bits*records/8;
  958.   if (new_length+1 < min_pack)
  959.   {
  960.     min_pos= -1;
  961.     min_pack=new_length;
  962.     min_space_count=space_count;
  963.   }
  964. /* Test with length-flag */
  965.   for (skipp=0L, i=0 ; i < 8 ; i++)
  966.   {
  967.     if (space_counts[i])
  968.     {
  969.       if (i)
  970. huff_counts->counts[(uint) ' ']+=space_counts[i];
  971.       skipp+=huff_counts->pre_space[i];
  972.       new_length=calc_packed_length(huff_counts,0)+
  973. (records+(records-skipp)*(1+length_bits))/8;
  974.       if (new_length < min_pack)
  975.       {
  976. min_pos=(int) i;
  977. min_pack=new_length;
  978. min_space_count=huff_counts->counts[(uint) ' '];
  979.       }
  980.     }
  981.   }
  982.   huff_counts->counts[(uint) ' ']=min_space_count;
  983.   huff_counts->bytes_packed=min_pack;
  984.   switch (min_pos) {
  985.   case -2:
  986.     return(0); /* No space-compress */
  987.   case -1: /* Always space-count */
  988.     huff_counts->field_type=field_type;
  989.     huff_counts->min_space=0;
  990.     huff_counts->length_bits=max_bit(max_space_length);
  991.     break;
  992.   default:
  993.     huff_counts->field_type=field_type;
  994.     huff_counts->min_space=(uint) min_pos;
  995.     huff_counts->pack_type|=PACK_TYPE_SELECTED;
  996.     huff_counts->length_bits=max_bit(max_space_length);
  997.     break;
  998.   }
  999.   return(1); /* Using space-compress */
  1000. }
  1001. /* Make a huff_tree of each huff_count */
  1002. static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
  1003. {
  1004.   uint tree;
  1005.   HUFF_TREE *huff_tree;
  1006.   DBUG_ENTER("make_huff_trees");
  1007.   if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
  1008.  MYF(MY_WME | MY_ZEROFILL))))
  1009.     DBUG_RETURN(0);
  1010.   for (tree=0 ; tree < trees ; tree++)
  1011.   {
  1012.     if (make_huff_tree(huff_tree+tree,huff_counts+tree))
  1013.     {
  1014.       while (tree--)
  1015. my_free((gptr) huff_tree[tree].element_buffer,MYF(0));
  1016.       my_free((gptr) huff_tree,MYF(0));
  1017.       DBUG_RETURN(0);
  1018.     }
  1019.   }
  1020.   DBUG_RETURN(huff_tree);
  1021. }
  1022. /* Update huff_tree according to huff_counts->counts or
  1023.    huff_counts->tree_buff */
  1024. static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
  1025. {
  1026.   uint i,found,bits_packed,first,last;
  1027.   my_off_t bytes_packed;
  1028.   HUFF_ELEMENT *a,*b,*new;
  1029.   first=last=0;
  1030.   if (huff_counts->tree_buff)
  1031.   {
  1032.     found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
  1033.       huff_counts->field_length;
  1034.     first=0; last=found-1;
  1035.   }
  1036.   else
  1037.   {
  1038.     for (i=found=0 ; i < 256 ; i++)
  1039.     {
  1040.       if (huff_counts->counts[i])
  1041.       {
  1042. if (! found++)
  1043.   first=i;
  1044. last=i;
  1045.       }
  1046.     }
  1047.     if (found < 2)
  1048.       found=2;
  1049.   }
  1050.   if (queue.max_elements < found)
  1051.   {
  1052.     delete_queue(&queue);
  1053.     if (init_queue(&queue,found,0,0,compare_huff_elements,0))
  1054.       return -1;
  1055.   }
  1056.   if (!huff_tree->element_buffer)
  1057.   {
  1058.     if (!(huff_tree->element_buffer=
  1059.  (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
  1060.       return 1;
  1061.   }
  1062.   else
  1063.   {
  1064.     HUFF_ELEMENT *temp;
  1065.     if (!(temp=
  1066.   (HUFF_ELEMENT*) my_realloc((gptr) huff_tree->element_buffer,
  1067.      found*2*sizeof(HUFF_ELEMENT),
  1068.      MYF(MY_WME))))
  1069.       return 1;
  1070.     huff_tree->element_buffer=temp;
  1071.   }
  1072.   huff_counts->tree=huff_tree;
  1073.   huff_tree->counts=huff_counts;
  1074.   huff_tree->min_chr=first;
  1075.   huff_tree->max_chr=last;
  1076.   huff_tree->char_bits=max_bit(last-first);
  1077.   huff_tree->offset_bits=max_bit(found-1)+1;
  1078.   if (huff_counts->tree_buff)
  1079.   {
  1080.     huff_tree->elements=0;
  1081.     tree_walk(&huff_counts->int_tree,
  1082.       (int (*)(void*, element_count,void*)) save_counts_in_queue,
  1083.       (gptr) huff_tree, left_root_right);
  1084.     huff_tree->tree_pack_length=(1+15+16+5+5+
  1085.  (huff_tree->char_bits+1)*found+
  1086.  (huff_tree->offset_bits+1)*
  1087.  (found-2)+7)/8 +
  1088.    (uint) (huff_tree->counts->tree_pos-
  1089.    huff_tree->counts->tree_buff);
  1090.   }
  1091.   else
  1092.   {
  1093.     huff_tree->elements=found;
  1094.     huff_tree->tree_pack_length=(9+9+5+5+
  1095.  (huff_tree->char_bits+1)*found+
  1096.  (huff_tree->offset_bits+1)*
  1097.  (found-2)+7)/8;
  1098.     for (i=first, found=0 ; i <= last ; i++)
  1099.     {
  1100.       if (huff_counts->counts[i])
  1101.       {
  1102. new=huff_tree->element_buffer+(found++);
  1103. new->count=huff_counts->counts[i];
  1104. new->a.leaf.null=0;
  1105. new->a.leaf.element_nr=i;
  1106. queue.root[found]=(byte*) new;
  1107.       }
  1108.     }
  1109.     while (found < 2)
  1110.     { /* Our huff_trees request at least 2 elements */
  1111.       new=huff_tree->element_buffer+(found++);
  1112.       new->count=0;
  1113.       new->a.leaf.null=0;
  1114.       if (last)
  1115. new->a.leaf.element_nr=huff_tree->min_chr=last-1;
  1116.       else
  1117. new->a.leaf.element_nr=huff_tree->max_chr=last+1;
  1118.       queue.root[found]=(byte*) new;
  1119.     }
  1120.   }
  1121.   queue.elements=found;
  1122.   for (i=found/2 ; i > 0 ; i--)
  1123.     _downheap(&queue,i);
  1124.   bytes_packed=0; bits_packed=0;
  1125.   for (i=1 ; i < found ; i++)
  1126.   {
  1127.     a=(HUFF_ELEMENT*) queue_remove(&queue,0);
  1128.     b=(HUFF_ELEMENT*) queue.root[1];
  1129.     new=huff_tree->element_buffer+found+i;
  1130.     new->count=a->count+b->count;
  1131.     bits_packed+=(uint) (new->count & 7);
  1132.     bytes_packed+=new->count/8;
  1133.     new->a.nod.left=a; /* lesser in left  */
  1134.     new->a.nod.right=b;
  1135.     queue.root[1]=(byte*) new;
  1136.     queue_replaced(&queue);
  1137.   }
  1138.   huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
  1139.   huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
  1140.   return 0;
  1141. }
  1142. static int compare_tree(register const uchar *s, register const uchar *t)
  1143. {
  1144.   uint length;
  1145.   for (length=global_count->field_length; length-- ;)
  1146.     if (*s++ != *t++)
  1147.       return (int) s[-1] - (int) t[-1];
  1148.   return 0;
  1149. }
  1150. /* Used by make_huff_tree to save intervall-counts in queue */
  1151. static int save_counts_in_queue(byte *key, element_count count, HUFF_TREE *tree)
  1152. {
  1153.   HUFF_ELEMENT *new;
  1154.   new=tree->element_buffer+(tree->elements++);
  1155.   new->count=count;
  1156.   new->a.leaf.null=0;
  1157.   new->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
  1158.     tree->counts->field_length;
  1159.   queue.root[tree->elements]=(byte*) new;
  1160.   return 0;
  1161. }
  1162. /* Calculate length of file if given counts should be used */
  1163. /* Its actually a faster version of make_huff_tree */
  1164. static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts, uint add_tree_lenght)
  1165. {
  1166.   uint i,found,bits_packed,first,last;
  1167.   my_off_t bytes_packed;
  1168.   HUFF_ELEMENT element_buffer[256];
  1169.   DBUG_ENTER("calc_packed_length");
  1170.   first=last=0;
  1171.   for (i=found=0 ; i < 256 ; i++)
  1172.   {
  1173.     if (huff_counts->counts[i])
  1174.     {
  1175.       if (! found++)
  1176. first=i;
  1177.       last=i;
  1178.       queue.root[found]=(byte*) &huff_counts->counts[i];
  1179.     }
  1180.   }
  1181.   if (!found)
  1182.     DBUG_RETURN(0); /* Empty tree */
  1183.   if (found < 2)
  1184.     queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1];
  1185.   queue.elements=found;
  1186.   bytes_packed=0; bits_packed=0;
  1187.   if (add_tree_lenght)
  1188.     bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
  1189.   (max_bit(found-1)+1+1)*(found-2) +7)/8;
  1190.   for (i=(found+1)/2 ; i > 0 ; i--)
  1191.     _downheap(&queue,i);
  1192.   for (i=0 ; i < found-1 ; i++)
  1193.   {
  1194.     HUFF_ELEMENT *a,*b,*new;
  1195.     a=(HUFF_ELEMENT*) queue_remove(&queue,0);
  1196.     b=(HUFF_ELEMENT*) queue.root[1];
  1197.     new=element_buffer+i;
  1198.     new->count=a->count+b->count;
  1199.     bits_packed+=(uint) (new->count & 7);
  1200.     bytes_packed+=new->count/8;
  1201.     queue.root[1]=(byte*) new;
  1202.     queue_replaced(&queue);
  1203.   }
  1204.   DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
  1205. }
  1206. /* Remove trees that don't give any compression */
  1207. static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
  1208. {
  1209.   uint k,tree_number;
  1210.   HUFF_COUNTS count,*i,*j,*last_count;
  1211.   last_count=huff_counts+trees;
  1212.   for (tree_number=0, i=huff_counts ; i < last_count ; i++)
  1213.   {
  1214.     if (!i->tree->tree_number)
  1215.     {
  1216.       i->tree->tree_number= ++tree_number;
  1217.       if (i->tree_buff)
  1218. continue; /* Don't join intervall */
  1219.       for (j=i+1 ; j < last_count ; j++)
  1220.       {
  1221. if (! j->tree->tree_number && ! j->tree_buff)
  1222. {
  1223.   for (k=0 ; k < 256 ; k++)
  1224.     count.counts[k]=i->counts[k]+j->counts[k];
  1225.   if (calc_packed_length(&count,1) <=
  1226.       i->tree->bytes_packed + j->tree->bytes_packed+
  1227.       i->tree->tree_pack_length+j->tree->tree_pack_length+
  1228.       ALLOWED_JOIN_DIFF)
  1229.   {
  1230.     memcpy((byte*) i->counts,(byte*) count.counts,
  1231.    sizeof(count.counts[0])*256);
  1232.     my_free((gptr) j->tree->element_buffer,MYF(0));
  1233.     j->tree->element_buffer=0;
  1234.     j->tree=i->tree;
  1235.     bmove((byte*) i->counts,(byte*) count.counts,
  1236.   sizeof(count.counts[0])*256);
  1237.     if (make_huff_tree(i->tree,i))
  1238.       return (uint) -1;
  1239.   }
  1240. }
  1241.       }
  1242.     }
  1243.   }
  1244.   if (verbose)
  1245.     printf("Original trees:  %d  After join: %dn",trees,tree_number);
  1246.   return tree_number; /* Return trees left */
  1247. }
  1248. /* Fill in huff_tree decode tables */
  1249. static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
  1250. {
  1251.   uint elements;
  1252.   for ( ; trees-- ; huff_tree++)
  1253.   {
  1254.     if (huff_tree->tree_number > 0)
  1255.     {
  1256.       elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
  1257.       if (!(huff_tree->code =
  1258.     (ulong*) my_malloc(elements*
  1259.        (sizeof(ulong)+sizeof(uchar)),
  1260.        MYF(MY_WME | MY_ZEROFILL))))
  1261. return 1;
  1262.       huff_tree->code_len=(uchar*) (huff_tree->code+elements);
  1263.       make_traverse_code_tree(huff_tree,huff_tree->root,32,0);
  1264.     }
  1265.   }
  1266.   return 0;
  1267. }
  1268. static void make_traverse_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
  1269.     uint size, ulong code)
  1270. {
  1271.   uint chr;
  1272.   if (!element->a.leaf.null)
  1273.   {
  1274.     chr=element->a.leaf.element_nr;
  1275.     huff_tree->code_len[chr]=(uchar) (32-size);
  1276.     huff_tree->code[chr]=    (code >> size);
  1277.     if (huff_tree->height < 32-size)
  1278.       huff_tree->height= 32-size;
  1279.   }
  1280.   else
  1281.   {
  1282.     size--;
  1283.     make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
  1284.     make_traverse_code_tree(huff_tree,element->a.nod.right,size,
  1285.     code+((ulong) 1L << size));
  1286.   }
  1287.   return;
  1288. }
  1289. /* Write header to new packed data file */
  1290. static int write_header(MRG_INFO *mrg,uint head_length,uint trees,
  1291. my_off_t tot_elements,my_off_t filelength)
  1292. {
  1293.   byte *buff=file_buffer.pos;
  1294.   bzero(buff,HEAD_LENGTH);
  1295.   memcpy(buff,nisam_pack_file_magic,4);
  1296.   int4store(buff+4,head_length);
  1297.   int4store(buff+8, mrg->min_pack_length);
  1298.   int4store(buff+12,mrg->max_pack_length);
  1299.   int4store(buff+16,tot_elements);
  1300.   int4store(buff+20,intervall_length);
  1301.   int2store(buff+24,trees);
  1302.   buff[26]=(char) mrg->ref_length;
  1303. /* Save record pointer length */
  1304.   buff[27]= (uchar) (filelength >= (1L << 24) ? 4 :
  1305.      filelength >= (1L << 16) ? 3 : 2);
  1306.   if (test_only)
  1307.     return 0;
  1308.   VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
  1309.   return my_write(file_buffer.file,file_buffer.pos,HEAD_LENGTH,
  1310.   MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
  1311. }
  1312. /* Write fieldinfo to new packed file */
  1313. static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
  1314. {
  1315.   reg1 uint i;
  1316.   uint huff_tree_bits;
  1317.   huff_tree_bits=max_bit(trees ? trees-1 : 0);
  1318.   for (i=0 ; i++ < fields ; counts++)
  1319.   {
  1320.     write_bits((ulong) (int) counts->field_type,4);
  1321.     write_bits(counts->pack_type,4);
  1322.     if (counts->pack_type & PACK_TYPE_ZERO_FILL)
  1323.       write_bits(counts->max_zero_fill,4);
  1324.     else
  1325.       write_bits(counts->length_bits,4);
  1326.     write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits);
  1327.   }
  1328.   flush_bits();
  1329.   return;
  1330. }
  1331. /* Write all huff_trees to new datafile. Return tot count of
  1332.    elements in all trees
  1333.    Returns 0 on error */
  1334. static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
  1335. {
  1336.   uint i,int_length;
  1337.   uint *packed_tree,*offset,length;
  1338.   my_off_t elements;
  1339.   for (i=length=0 ; i < trees ; i++)
  1340.     if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
  1341.       length=huff_tree[i].elements;
  1342.   if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
  1343.   {
  1344.     my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
  1345.     return 0;
  1346.   }
  1347.   intervall_length=0;
  1348.   for (elements=0; trees-- ; huff_tree++)
  1349.   {
  1350.     if (huff_tree->tree_number == 0)
  1351.       continue; /* Deleted tree */
  1352.     elements+=huff_tree->elements;
  1353.     huff_tree->max_offset=2;
  1354.     if (huff_tree->elements <= 1)
  1355.       offset=packed_tree;
  1356.     else
  1357.       offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
  1358.     huff_tree->offset_bits=max_bit(huff_tree->max_offset);
  1359.     if (huff_tree->max_offset >= IS_OFFSET)
  1360.     { /* This should be impossible */
  1361.       VOID(fprintf(stderr,"Tree offset got too big: %d, abortedn",
  1362.       huff_tree->max_offset));
  1363.       my_afree((gptr) packed_tree);
  1364.       return 0;
  1365.     }
  1366. #ifdef EXTRA_DBUG
  1367.     printf("pos: %d  elements: %d  tree-elements: %d  char_bits: %dn",
  1368.    (uint) (file_buffer.pos-file_buffer.buffer),
  1369.    huff_tree->elements,  (offset-packed_tree),huff_tree->char_bits);
  1370. #endif
  1371.     if (!huff_tree->counts->tree_buff)
  1372.     {
  1373.       write_bits(0,1);
  1374.       write_bits(huff_tree->min_chr,8);
  1375.       write_bits(huff_tree->elements,9);
  1376.       write_bits(huff_tree->char_bits,5);
  1377.       write_bits(huff_tree->offset_bits,5);
  1378.       int_length=0;
  1379.     }
  1380.     else
  1381.     {
  1382.       int_length=(uint) (huff_tree->counts->tree_pos -
  1383.  huff_tree->counts->tree_buff);
  1384.       write_bits(1,1);
  1385.       write_bits(huff_tree->elements,15);
  1386.       write_bits(int_length,16);
  1387.       write_bits(huff_tree->char_bits,5);
  1388.       write_bits(huff_tree->offset_bits,5);
  1389.       intervall_length+=int_length;
  1390.     }
  1391.     length=(uint) (offset-packed_tree);
  1392.     if (length != huff_tree->elements*2-2)
  1393.       printf("error: Huff-tree-length: %d != calc_length: %dn",
  1394.      length,huff_tree->elements*2-2);
  1395.     for (i=0 ; i < length ; i++)
  1396.     {
  1397.       if (packed_tree[i] & IS_OFFSET)
  1398. write_bits(packed_tree[i] - IS_OFFSET+ ((ulong) 1L << huff_tree->offset_bits),
  1399.    huff_tree->offset_bits+1);
  1400.       else
  1401. write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
  1402.     }
  1403.     flush_bits();
  1404.     if (huff_tree->counts->tree_buff)
  1405.     {
  1406.       for (i=0 ; i < int_length ; i++)
  1407. write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8);
  1408.     }
  1409.     flush_bits();
  1410.   }
  1411.   my_afree((gptr) packed_tree);
  1412.   return elements;
  1413. }
  1414. static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
  1415.    uint *offset)
  1416. {
  1417.   uint *prev_offset;
  1418.   prev_offset= offset;
  1419.   if (!element->a.nod.left->a.leaf.null)
  1420.   {
  1421.     offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
  1422.     offset+=2;
  1423.   }
  1424.   else
  1425.   {
  1426.     prev_offset[0]= IS_OFFSET+2;
  1427.     offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
  1428.   }
  1429.   if (!element->a.nod.right->a.leaf.null)
  1430.   {
  1431.     prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
  1432.     return offset;
  1433.   }
  1434.   else
  1435.   {
  1436.     uint temp=(uint) (offset-prev_offset-1);
  1437.     prev_offset[1]= IS_OFFSET+ temp;
  1438.     if (huff_tree->max_offset < temp)
  1439.       huff_tree->max_offset = temp;
  1440.     return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
  1441.   }
  1442. }
  1443. /* Get number of bits neaded to represent value */
  1444. static uint max_bit(register uint value)
  1445. {
  1446.   reg2 uint power=1;
  1447.   while ((value>>=1))
  1448.     power++;
  1449.   return (power);
  1450. }
  1451. static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
  1452. {
  1453.   int error;
  1454.   uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
  1455.   intervall,field_length;
  1456.   my_off_t record_count,max_allowed_length;
  1457.   ulong length;
  1458.   byte *record,*pos,*end_pos,*record_pos,*start_pos;
  1459.   HUFF_COUNTS *count,*end_count;
  1460.   HUFF_TREE *tree;
  1461.   N_INFO *isam_file=mrg->file[0];
  1462.   DBUG_ENTER("compress_isam_file");
  1463.   if (!(record=(byte*) my_alloca(isam_file->s->base.reclength)))
  1464.     return -1;
  1465.   end_count=huff_counts+isam_file->s->base.fields;
  1466.   min_record_length= (uint) ~0;
  1467.   max_record_length=0;
  1468.   for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
  1469.   {
  1470.     if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
  1471.       huff_counts[i].max_zero_fill=0;
  1472.     if (huff_counts[i].field_type == FIELD_CONSTANT ||
  1473. huff_counts[i].field_type == FIELD_ZERO)
  1474.       continue;
  1475.     if (huff_counts[i].field_type == FIELD_INTERVALL)
  1476.       max_calc_length+=huff_counts[i].tree->height;
  1477.     else
  1478.       max_calc_length+=
  1479. (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
  1480.   huff_counts[i].tree->height+huff_counts[i].length_bits;
  1481.   }
  1482.   max_calc_length/=8;
  1483.   if (max_calc_length <= 255)
  1484.     pack_ref_length=1;
  1485.   else if (max_calc_length <= 65535)
  1486.     pack_ref_length=2;
  1487.   else
  1488.     pack_ref_length=3;
  1489.   if (force_pack_ref_length)
  1490.     pack_ref_length=force_pack_ref_length;
  1491.   max_allowed_length= 1L << (pack_ref_length*8);
  1492.   record_count=0;
  1493.   mrg_reset(mrg);
  1494.   while ((error=mrg_rrnd(mrg,record)) >= 0)
  1495.   {
  1496.     if (! error)
  1497.     {
  1498.       if (flush_buffer(max_calc_length+pack_ref_length))
  1499. break;
  1500.       record_pos=file_buffer.pos;
  1501.       file_buffer.pos+=pack_ref_length;
  1502.       for (start_pos=record, count= huff_counts; count < end_count ; count++)
  1503.       {
  1504. end_pos=start_pos+(field_length=count->field_length);
  1505. tree=count->tree;
  1506. if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
  1507. {
  1508.   for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
  1509.   if (pos == end_pos)
  1510.   {
  1511.     write_bits(1,1);
  1512.     start_pos=end_pos;
  1513.     continue;
  1514.   }
  1515.   write_bits(0,1);
  1516. }
  1517. #ifdef BYTE_ORDER_HIGH_FIRST
  1518. start_pos+=count->max_zero_fill;
  1519. #else
  1520. end_pos-=count->max_zero_fill;
  1521. #endif
  1522. field_length-=count->max_zero_fill;
  1523. switch(count->field_type) {
  1524. case FIELD_SKIPP_ZERO:
  1525.   if (!memcmp((byte*) start_pos,zero_string,field_length))
  1526.   {
  1527.     write_bits(1,1);
  1528.     start_pos=end_pos;
  1529.     break;
  1530.   }
  1531.   write_bits(0,1);
  1532.   /* Fall through */
  1533. case FIELD_NORMAL:
  1534.   for ( ; start_pos < end_pos ; start_pos++)
  1535.     write_bits(tree->code[(uchar) *start_pos],
  1536.        (uint) tree->code_len[(uchar) *start_pos]);
  1537.   break;
  1538. case FIELD_SKIPP_ENDSPACE:
  1539.   for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
  1540.   length=(uint) (end_pos-pos);
  1541.   if (count->pack_type & PACK_TYPE_SELECTED)
  1542.   {
  1543.     if (length > count->min_space)
  1544.     {
  1545.       write_bits(1,1);
  1546.       write_bits(length,count->length_bits);
  1547.     }
  1548.     else
  1549.     {
  1550.       write_bits(0,1);
  1551.       pos=end_pos;
  1552.     }
  1553.   }
  1554.   else
  1555.     write_bits(length,count->length_bits);
  1556.   for ( ; start_pos < pos ; start_pos++)
  1557.     write_bits(tree->code[(uchar) *start_pos],
  1558.        (uint) tree->code_len[(uchar) *start_pos]);
  1559.   start_pos=end_pos;
  1560.   break;
  1561. case FIELD_SKIPP_PRESPACE:
  1562.   for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
  1563.   length=(uint) (pos-start_pos);
  1564.   if (count->pack_type & PACK_TYPE_SELECTED)
  1565.   {
  1566.     if (length > count->min_space)
  1567.     {
  1568.       write_bits(1,1);
  1569.       write_bits(length,count->length_bits);
  1570.     }
  1571.     else
  1572.     {
  1573.       pos=start_pos;
  1574.       write_bits(0,1);
  1575.     }
  1576.   }
  1577.   else
  1578.     write_bits(length,count->length_bits);
  1579.   for (start_pos=pos ; start_pos < end_pos ; start_pos++)
  1580.     write_bits(tree->code[(uchar) *start_pos],
  1581.        (uint) tree->code_len[(uchar) *start_pos]);
  1582.   break;
  1583. case FIELD_CONSTANT:
  1584. case FIELD_ZERO:
  1585.   start_pos=end_pos;
  1586.   break;
  1587. case FIELD_INTERVALL:
  1588.   global_count=count;
  1589.   pos=(byte*) tree_search(&count->int_tree,start_pos);
  1590.   intervall=(uint) (pos - count->tree_buff)/field_length;
  1591.   write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
  1592.   start_pos=end_pos;
  1593.   break;
  1594. case FIELD_BLOB:
  1595.   VOID(fprintf(stderr,"Can't pack files with blobs. Abortingn"));
  1596.   DBUG_RETURN(1);
  1597. case FIELD_LAST:
  1598. case FIELD_VARCHAR:
  1599. case FIELD_CHECK:
  1600.   abort(); /* Impossible */
  1601. }
  1602. #ifndef BYTE_ORDER_HIGH_FIRST
  1603. start_pos+=count->max_zero_fill;
  1604. #endif
  1605.       }
  1606.       flush_bits();
  1607.       length=(ulong) (file_buffer.pos-record_pos)-pack_ref_length;
  1608.       save_integer(record_pos,pack_ref_length,length);
  1609.       if (length < (ulong) min_record_length)
  1610. min_record_length=(uint) length;
  1611.       if (length > (ulong) max_record_length)
  1612.       {
  1613. max_record_length=(uint) length;
  1614. if (max_record_length >= max_allowed_length)
  1615. {
  1616.   fprintf(stderr,
  1617.   "Error: Found record with packed-length: %d, max is: %lun",
  1618.   max_record_length, (ulong) max_allowed_length);
  1619.   error=1;
  1620.   break;
  1621. }
  1622.       }
  1623.       if (write_loop && ++record_count % WRITE_COUNT == 0)
  1624.       {
  1625. printf("%lur",(ulong) record_count); VOID(fflush(stdout));
  1626.       }
  1627.     }
  1628.     else if (my_errno != HA_ERR_RECORD_DELETED)
  1629.       break;
  1630.   }
  1631.   if (error < 0)
  1632.   {
  1633.     error=0;
  1634.     if (my_errno != HA_ERR_END_OF_FILE)
  1635.     {
  1636.       fprintf(stderr,"%s: Got error %d reading recordsn",my_progname,my_errno);
  1637.       error= 1;
  1638.     }
  1639.   }
  1640.   my_afree((gptr) record);
  1641.   mrg->ref_length=pack_ref_length;
  1642.   mrg->min_pack_length=max_record_length ? min_record_length : 0;
  1643.   mrg->max_pack_length=max_record_length;
  1644.   if (verbose && max_record_length &&
  1645.       max_record_length < max_allowed_length/256)
  1646.     printf("Record-length is %d bytes, could have been %d bytesnYou can change this by using -p=%d next time you pack this filen",
  1647.    pack_ref_length,
  1648.    max_record_length/256+1,
  1649.    max_record_length/256+1);
  1650.   DBUG_RETURN(error || error_on_write || flush_buffer((uint) ~0));
  1651. }
  1652. static char *make_new_name(char *new_name, char *old_name)
  1653. {
  1654.   return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
  1655. }
  1656. static char *make_old_name(char *new_name, char *old_name)
  1657. {
  1658.   return fn_format(new_name,old_name,"",OLD_EXT,2+4);
  1659. }
  1660. /* rutines for bit writing buffer */
  1661. static void init_file_buffer(File file, pbool read_buffer)
  1662. {
  1663.   file_buffer.file=file;
  1664.   file_buffer.buffer=my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),MYF(MY_WME));
  1665.   file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-4;
  1666.   file_buffer.pos_in_file=0;
  1667.   error_on_write=0;
  1668.   if (read_buffer)
  1669.   {
  1670.     file_buffer.pos=file_buffer.end;
  1671.     file_buffer.bits=0;
  1672.   }
  1673.   else
  1674.   {
  1675.     file_buffer.pos=file_buffer.buffer;
  1676.     file_buffer.bits=BITS_SAVED;
  1677.   }
  1678.   file_buffer.byte=0;
  1679. }
  1680. static int flush_buffer(uint neaded_length)
  1681. {
  1682.   uint length;
  1683.   if ((uint) (file_buffer.end - file_buffer.pos) > neaded_length)
  1684.     return 0;
  1685.   length=(uint) (file_buffer.pos-file_buffer.buffer);
  1686.   file_buffer.pos=file_buffer.buffer;
  1687.   file_buffer.pos_in_file+=length;
  1688.   if (test_only)
  1689.     return 0;
  1690.   return (error_on_write|=test(my_write(file_buffer.file,file_buffer.buffer,
  1691. length,
  1692. MYF(MY_WME | MY_NABP |
  1693.     MY_WAIT_IF_FULL))));
  1694. }
  1695. static void end_file_buffer(void)
  1696. {
  1697.   my_free((gptr) file_buffer.buffer,MYF(0));
  1698. }
  1699. /* output `bits` low bits of `value' */
  1700. static void write_bits (register ulong value, register uint bits)
  1701. {
  1702.   if ((file_buffer.bits-=(int) bits) >= 0)
  1703.   {
  1704.     file_buffer.byte|=value << file_buffer.bits;
  1705.   }
  1706.   else
  1707.   {
  1708.     reg3 uint byte_buff;
  1709.     bits= (uint) -file_buffer.bits;
  1710.     byte_buff=file_buffer.byte | (uint) (value >> bits);
  1711. #if BITS_SAVED == 32
  1712.     *file_buffer.pos++= (byte) (byte_buff >> 24) ;
  1713.     *file_buffer.pos++= (byte) (byte_buff >> 16) ;
  1714. #endif
  1715.     *file_buffer.pos++= (byte) (byte_buff >> 8) ;
  1716.     *file_buffer.pos++= (byte) byte_buff;
  1717.     value&=((ulong) 1L << bits)-1;
  1718. #if BITS_SAVED == 16
  1719.     if (bits >= sizeof(uint))
  1720.     {
  1721.       bits-=8;
  1722.       *file_buffer.pos++= (uchar) (value >> bits);
  1723.       value&= ((ulong) 1L << bits)-1;
  1724.       if (bits >= sizeof(uint))
  1725.       {
  1726. bits-=8;
  1727. *file_buffer.pos++= (uchar) (value >> bits);
  1728. value&= ((ulong) 1L << bits)-1;
  1729.       }
  1730.     }
  1731. #endif
  1732.     if (file_buffer.pos >= file_buffer.end)
  1733.       VOID(flush_buffer((uint) ~0));
  1734.     file_buffer.bits=(int) (BITS_SAVED - bits);
  1735.     file_buffer.byte=(uint) (value << (BITS_SAVED - bits));
  1736.   }
  1737.   return;
  1738. }
  1739. /* Flush bits in bit_buffer to buffer */
  1740. static void flush_bits (void)
  1741. {
  1742.   uint bits,byte_buff;
  1743.   bits=(file_buffer.bits) & ~7;
  1744.   byte_buff = file_buffer.byte >> bits;
  1745.   bits=BITS_SAVED - bits;
  1746.   while (bits > 0)
  1747.   {
  1748.     bits-=8;
  1749.     *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ;
  1750.   }
  1751.   file_buffer.bits=BITS_SAVED;
  1752.   file_buffer.byte=0;
  1753.   return;
  1754. }
  1755. /* Store long in 1,2,3,4 or 5 bytes */
  1756. static void save_integer(byte *pos, uint pack_length, my_off_t value)
  1757. {
  1758.   switch (pack_length) {
  1759.   case 5: int5store(pos,(ulonglong) value); break;
  1760.   default: int4store(pos,(ulong) value); break;
  1761.   case 3: int3store(pos,(ulong) value);  break;
  1762.   case 2: int2store(pos,(uint) value); break;
  1763.   case 1: pos[0]= (byte) (uchar) value; break;
  1764.   }
  1765.   return;
  1766. }
  1767. /****************************************************************************
  1768. ** functions to handle the joined files
  1769. ****************************************************************************/
  1770. static void save_state(N_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
  1771.        ulong crc)
  1772. {
  1773.   ISAM_SHARE *share=isam_file->s;
  1774.   uint options=uint2korr(share->state.header.options);
  1775.   DBUG_ENTER("save_state");
  1776.   options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
  1777.   int2store(share->state.header.options,options);
  1778.   share->state.data_file_length=(ulong) new_length;
  1779.   share->state.del=share->state.empty=0;
  1780.   share->state.dellink= (ulong) NI_POS_ERROR;
  1781.   share->state.splitt=(ulong) mrg->records;
  1782.   share->state.version=(ulong) time((time_t*) 0);
  1783.   share->state.keys=0;
  1784.   share->state.key_file_length=share->base.keystart;
  1785.   isam_file->update|=(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
  1786.   isam_file->this_uniq=crc; /* Save crc here */
  1787.   share->changed=1; /* Force write of header */
  1788.   VOID(my_chsize(share->kfile,share->state.key_file_length,
  1789.  MYF(0)));
  1790.   if (share->state.keys != share->base.keys)
  1791.     isamchk_neaded=1;
  1792.   DBUG_VOID_RETURN;
  1793. }
  1794. static int save_state_mrg(File file,MRG_INFO *mrg,my_off_t new_length,
  1795.   ulong crc)
  1796. {
  1797.   N_STATE_INFO state;
  1798.   N_INFO *isam_file=mrg->file[0];
  1799.   uint options;
  1800.   DBUG_ENTER("save_state_mrg");
  1801.   memcpy(&state,&isam_file->s->state,sizeof(state));
  1802.   options= (uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
  1803.     HA_OPTION_READ_ONLY_DATA);
  1804.   int2store(state.header.options,options);
  1805.   state.data_file_length=(ulong) new_length;
  1806.   state.del=state.empty=0;
  1807.   state.dellink= (ulong) NI_POS_ERROR;
  1808.   state.records=state.splitt=(ulong) mrg->records;
  1809.   state.version=(ulong) time((time_t*) 0);
  1810.   state.keys=0;
  1811.   state.key_file_length=isam_file->s->base.keystart;
  1812.   state.uniq=crc;
  1813.   if (state.keys != isam_file->s->base.keys)
  1814.     isamchk_neaded=1;
  1815.   DBUG_RETURN (my_pwrite(file,(char*) &state.header,
  1816.  isam_file->s->state_length,0L,
  1817.  MYF(MY_NABP | MY_WME)) != 0);
  1818. }
  1819. /* reset for mrg_rrnd */
  1820. static void mrg_reset(MRG_INFO *mrg)
  1821. {
  1822.   if (mrg->current)
  1823.   {
  1824.     nisam_extra(*mrg->current,HA_EXTRA_NO_CACHE);
  1825.     mrg->current=0;
  1826.   }
  1827. }
  1828. static int mrg_rrnd(MRG_INFO *info,byte *buf)
  1829. {
  1830.   int error;
  1831.   N_INFO *isam_info;
  1832.   my_off_t filepos;
  1833.   if (!info->current)
  1834.   {
  1835.     isam_info= *(info->current=info->file);
  1836.     info->end=info->current+info->count;
  1837.     nisam_extra(isam_info,HA_EXTRA_RESET);
  1838.     nisam_extra(isam_info,HA_EXTRA_CACHE);
  1839.     filepos=isam_info->s->pack.header_length;
  1840.   }
  1841.   else
  1842.   {
  1843.     isam_info= *info->current;
  1844.     filepos= isam_info->nextpos;
  1845.   }
  1846.   for (;;)
  1847.   {
  1848.     isam_info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
  1849.     if ((error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
  1850.  (ulong) filepos, 1)) >= 0 ||
  1851. my_errno != HA_ERR_END_OF_FILE)
  1852.       return (error);
  1853.     nisam_extra(isam_info,HA_EXTRA_NO_CACHE);
  1854.     if (info->current+1 == info->end)
  1855.       return(-1);
  1856.     info->current++;
  1857.     isam_info= *info->current;
  1858.     filepos=isam_info->s->pack.header_length;
  1859.     nisam_extra(isam_info,HA_EXTRA_RESET);
  1860.     nisam_extra(isam_info,HA_EXTRA_CACHE);
  1861.   }
  1862. }
  1863. static int mrg_close(MRG_INFO *mrg)
  1864. {
  1865.   uint i;
  1866.   int error=0;
  1867.   for (i=0 ; i < mrg->count ; i++)
  1868.     error|=nisam_close(mrg->file[i]);
  1869.   return error;
  1870. }