pack_isam.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:56k
源码类别:

MySQL数据库

开发平台:

Visual C++

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