~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/myisampack.c

  • Committer: Jay Pipes
  • Date: 2008-07-17 17:54:00 UTC
  • mto: This revision was merged to the branch mainline in revision 182.
  • Revision ID: jay@mysql.com-20080717175400-xm2aazihjra8mdzq
Removal of DBUG from libdrizzle/ - Round 2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 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; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/* Pack MyISAM file */
 
17
 
 
18
#ifndef USE_MY_FUNC
 
19
#define USE_MY_FUNC                     /* We need at least my_malloc */
 
20
#endif
 
21
 
 
22
#include "myisamdef.h"
 
23
#include <queues.h>
 
24
#include <my_tree.h>
 
25
#include "mysys_err.h"
 
26
#ifndef __GNU_LIBRARY__
 
27
#define __GNU_LIBRARY__                 /* Skip warnings in getopt.h */
 
28
#endif
 
29
#include <my_getopt.h>
 
30
#include <assert.h>
 
31
 
 
32
#if SIZEOF_LONG_LONG > 4
 
33
#define BITS_SAVED 64
 
34
#else
 
35
#define BITS_SAVED 32
 
36
#endif
 
37
 
 
38
#define IS_OFFSET ((uint) 32768)        /* Bit if offset or char in tree */
 
39
#define HEAD_LENGTH     32
 
40
#define ALLOWED_JOIN_DIFF       256     /* Diff allowed to join trees */
 
41
 
 
42
#define DATA_TMP_EXT            ".TMD"
 
43
#define OLD_EXT                 ".OLD"
 
44
#define WRITE_COUNT             MY_HOW_OFTEN_TO_WRITE
 
45
 
 
46
struct st_file_buffer {
 
47
  File file;
 
48
  uchar *buffer,*pos,*end;
 
49
  my_off_t pos_in_file;
 
50
  int bits;
 
51
  uint64_t bitbucket;
 
52
};
 
53
 
 
54
struct st_huff_tree;
 
55
struct st_huff_element;
 
56
 
 
57
typedef struct st_huff_counts {
 
58
  uint  field_length,max_zero_fill;
 
59
  uint  pack_type;
 
60
  uint  max_end_space,max_pre_space,length_bits,min_space;
 
61
  ulong max_length;
 
62
  enum en_fieldtype field_type;
 
63
  struct st_huff_tree *tree;            /* Tree for field */
 
64
  my_off_t counts[256];
 
65
  my_off_t end_space[8];
 
66
  my_off_t pre_space[8];
 
67
  my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
 
68
  TREE int_tree;        /* Tree for detecting distinct column values. */
 
69
  uchar *tree_buff;      /* Column values, 'field_length' each. */
 
70
  uchar *tree_pos;       /* Points to end of column values in 'tree_buff'. */
 
71
} HUFF_COUNTS;
 
72
 
 
73
typedef struct st_huff_element HUFF_ELEMENT;
 
74
 
 
75
/*
 
76
  WARNING: It is crucial for the optimizations in calc_packed_length()
 
77
  that 'count' is the first element of 'HUFF_ELEMENT'.
 
78
*/
 
79
struct st_huff_element {
 
80
  my_off_t count;
 
81
  union un_element {
 
82
    struct st_nod {
 
83
      HUFF_ELEMENT *left,*right;
 
84
    } nod;
 
85
    struct st_leaf {
 
86
      HUFF_ELEMENT *null;
 
87
      uint      element_nr;             /* Number of element */
 
88
    } leaf;
 
89
  } a;
 
90
};
 
91
 
 
92
 
 
93
typedef struct st_huff_tree {
 
94
  HUFF_ELEMENT *root,*element_buffer;
 
95
  HUFF_COUNTS *counts;
 
96
  uint tree_number;
 
97
  uint elements;
 
98
  my_off_t bytes_packed;
 
99
  uint tree_pack_length;
 
100
  uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
 
101
  uint64_t *code;
 
102
  uchar *code_len;
 
103
} HUFF_TREE;
 
104
 
 
105
 
 
106
typedef struct st_isam_mrg {
 
107
  MI_INFO **file,**current,**end;
 
108
  uint free_file;
 
109
  uint count;
 
110
  uint  min_pack_length;                /* Theese is used by packed data */
 
111
  uint  max_pack_length;
 
112
  uint  ref_length;
 
113
  uint  max_blob_length;
 
114
  my_off_t records;
 
115
  /* true if at least one source file has at least one disabled index */
 
116
  my_bool src_file_has_indexes_disabled;
 
117
} PACK_MRG_INFO;
 
118
 
 
119
 
 
120
extern int main(int argc,char * *argv);
 
121
static void get_options(int *argc,char ***argv);
 
122
static MI_INFO *open_isam_file(char *name,int mode);
 
123
static my_bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count);
 
124
static int compress(PACK_MRG_INFO *file,char *join_name);
 
125
static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records);
 
126
static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
 
127
                                           uint trees,
 
128
                                           HUFF_COUNTS *huff_counts,
 
129
                                           uint fields);
 
130
static int compare_tree(void* cmp_arg __attribute__((unused)),
 
131
                        const uchar *s,const uchar *t);
 
132
static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
 
133
static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
 
134
                         my_off_t records);
 
135
static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
 
136
                               uint max_space_length,my_off_t *space_counts,
 
137
                               my_off_t tot_space_count,
 
138
                               enum en_fieldtype field_type);
 
139
static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
 
140
static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
 
141
static int compare_huff_elements(void *not_used, uchar *a,uchar *b);
 
142
static int save_counts_in_queue(uchar *key,element_count count,
 
143
                                    HUFF_TREE *tree);
 
144
static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
 
145
static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
 
146
static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
 
147
static void make_traverse_code_tree(HUFF_TREE *huff_tree,
 
148
                                    HUFF_ELEMENT *element,uint size,
 
149
                                    uint64_t code);
 
150
static int write_header(PACK_MRG_INFO *isam_file, uint header_length,uint trees,
 
151
                        my_off_t tot_elements,my_off_t filelength);
 
152
static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
 
153
static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
 
154
static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
 
155
                                       HUFF_ELEMENT *element,
 
156
                                       uint *offset);
 
157
static uint max_bit(uint value);
 
158
static int compress_isam_file(PACK_MRG_INFO *file,HUFF_COUNTS *huff_counts);
 
159
static char *make_new_name(char *new_name,char *old_name);
 
160
static char *make_old_name(char *new_name,char *old_name);
 
161
static void init_file_buffer(File file,bool read_buffer);
 
162
static int flush_buffer(ulong neaded_length);
 
163
static void end_file_buffer(void);
 
164
static void write_bits(uint64_t value, uint bits);
 
165
static void flush_bits(void);
 
166
static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length,
 
167
                      ha_checksum crc);
 
168
static int save_state_mrg(File file,PACK_MRG_INFO *isam_file,my_off_t new_length,
 
169
                          ha_checksum crc);
 
170
static int mrg_close(PACK_MRG_INFO *mrg);
 
171
static int mrg_rrnd(PACK_MRG_INFO *info,uchar *buf);
 
172
static void mrg_reset(PACK_MRG_INFO *mrg);
 
173
 
 
174
static int error_on_write=0,test_only=0,verbose=0,silent=0,
 
175
           write_loop=0,force_pack=0, isamchk_neaded=0;
 
176
static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
 
177
static my_bool backup, opt_wait;
 
178
/*
 
179
  tree_buff_length is somewhat arbitrary. The bigger it is the better
 
180
  the chance to win in terms of compression factor. On the other hand,
 
181
  this table becomes part of the compressed file header. And its length
 
182
  is coded with 16 bits in the header. Hence the limit is 2**16 - 1.
 
183
*/
 
184
static uint tree_buff_length= 65536 - MALLOC_OVERHEAD;
 
185
static char tmp_dir[FN_REFLEN]={0},*join_table;
 
186
static my_off_t intervall_length;
 
187
static ha_checksum glob_crc;
 
188
static struct st_file_buffer file_buffer;
 
189
static QUEUE queue;
 
190
static HUFF_COUNTS *global_count;
 
191
static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
192
static const char *load_default_groups[]= { "myisampack",0 };
 
193
 
 
194
        /* The main program */
 
195
 
 
196
int main(int argc, char **argv)
 
197
{
 
198
  int error,ok;
 
199
  PACK_MRG_INFO merge;
 
200
  char **default_argv;
 
201
  MY_INIT(argv[0]);
 
202
 
 
203
  load_defaults("my",load_default_groups,&argc,&argv);
 
204
  default_argv= argv;
 
205
  get_options(&argc,&argv);
 
206
 
 
207
  error=ok=isamchk_neaded=0;
 
208
  if (join_table)
 
209
  {                                             /* Join files into one */
 
210
    if (open_isam_files(&merge,argv,(uint) argc) ||
 
211
        compress(&merge,join_table))
 
212
      error=1;
 
213
  }
 
214
  else while (argc--)
 
215
  {
 
216
    MI_INFO *isam_file;
 
217
    if (!(isam_file=open_isam_file(*argv++,O_RDWR)))
 
218
      error=1;
 
219
    else
 
220
    {
 
221
      merge.file= &isam_file;
 
222
      merge.current=0;
 
223
      merge.free_file=0;
 
224
      merge.count=1;
 
225
      if (compress(&merge,0))
 
226
        error=1;
 
227
      else
 
228
        ok=1;
 
229
    }
 
230
  }
 
231
  if (ok && isamchk_neaded && !silent)
 
232
    puts("Remember to run myisamchk -rq on compressed tables");
 
233
  VOID(fflush(stdout));
 
234
  VOID(fflush(stderr));
 
235
  free_defaults(default_argv);
 
236
  my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
 
237
  exit(error ? 2 : 0);
 
238
#ifndef _lint
 
239
  return 0;                                     /* No compiler warning */
 
240
#endif
 
241
}
 
242
 
 
243
enum options_mp {OPT_CHARSETS_DIR_MP=256, OPT_AUTO_CLOSE};
 
244
 
 
245
static struct my_option my_long_options[] =
 
246
{
 
247
#ifdef __NETWARE__
 
248
  {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
 
249
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
250
#endif
 
251
  {"backup", 'b', "Make a backup of the table as table_name.OLD.",
 
252
   (char**) &backup, (char**) &backup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
253
  {"character-sets-dir", OPT_CHARSETS_DIR_MP,
 
254
   "Directory where character sets are.", (char**) &charsets_dir,
 
255
   (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
256
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
 
257
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
258
  {"force", 'f',
 
259
   "Force packing of table even if it gets bigger or if tempfile exists.",
 
260
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
261
  {"join", 'j',
 
262
   "Join all given tables into 'new_table_name'. All tables MUST have identical layouts.",
 
263
   (char**) &join_table, (char**) &join_table, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
 
264
   0, 0, 0},
 
265
  {"help", '?', "Display this help and exit.",
 
266
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
267
  {"silent", 's', "Be more silent.",
 
268
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
269
  {"tmpdir", 'T', "Use temporary directory to store temporary table.",
 
270
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
271
  {"test", 't', "Don't pack table, only test packing it.",
 
272
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
273
  {"verbose", 'v', "Write info about progress and packing result. Use many -v for more verbosity!",
 
274
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
275
  {"version", 'V', "Output version information and exit.",
 
276
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
277
  {"wait", 'w', "Wait and retry if table is in use.", (char**) &opt_wait,
 
278
   (char**) &opt_wait, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
279
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
280
};
 
281
 
 
282
#include <help_start.h>
 
283
 
 
284
static void print_version(void)
 
285
{
 
286
  VOID(printf("%s Ver 1.23 for %s on %s\n",
 
287
              my_progname, SYSTEM_TYPE, MACHINE_TYPE));
 
288
}
 
289
 
 
290
 
 
291
static void usage(void)
 
292
{
 
293
  print_version();
 
294
  puts("Copyright (C) 2002 MySQL AB");
 
295
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
 
296
  puts("and you are welcome to modify and redistribute it under the GPL license\n");
 
297
 
 
298
  puts("Pack a MyISAM-table to take much less space.");
 
299
  puts("Keys are not updated, you must run myisamchk -rq on the datafile");
 
300
  puts("afterwards to update the keys.");
 
301
  puts("You should give the .MYI file as the filename argument.");
 
302
 
 
303
  VOID(printf("\nUsage: %s [OPTIONS] filename...\n", my_progname));
 
304
  my_print_help(my_long_options);
 
305
  print_defaults("my", load_default_groups);
 
306
  my_print_variables(my_long_options);
 
307
}
 
308
 
 
309
#include <help_end.h>
 
310
 
 
311
static bool
 
312
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
 
313
               char *argument)
 
314
{
 
315
  uint length;
 
316
 
 
317
  switch(optid) {
 
318
#ifdef __NETWARE__
 
319
  case OPT_AUTO_CLOSE:
 
320
    setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
 
321
    break;
 
322
#endif
 
323
  case 'f':
 
324
    force_pack= 1;
 
325
    tmpfile_createflag= O_RDWR | O_TRUNC;
 
326
    break;
 
327
  case 's':
 
328
    write_loop= verbose= 0;
 
329
    silent= 1;
 
330
    break;
 
331
  case 't':
 
332
    test_only= 1;
 
333
    /* Avoid to reset 'verbose' if it was already set > 1. */
 
334
    if (! verbose)
 
335
      verbose= 1;
 
336
    break;
 
337
  case 'T':
 
338
    length= (uint) (strmov(tmp_dir, argument) - tmp_dir);
 
339
    if (length != dirname_length(tmp_dir))
 
340
    {
 
341
      tmp_dir[length]=FN_LIBCHAR;
 
342
      tmp_dir[length+1]=0;
 
343
    }
 
344
    break;
 
345
  case 'v':
 
346
    verbose++; /* Allow for selecting the level of verbosity. */
 
347
    silent= 0;
 
348
    break;
 
349
  case 'V':
 
350
    print_version();
 
351
    exit(0);
 
352
  case 'I':
 
353
  case '?':
 
354
    usage();
 
355
    exit(0);
 
356
  }
 
357
  return 0;
 
358
}
 
359
 
 
360
        /* reads options */
 
361
        /* Initiates DEBUG - but no debugging here ! */
 
362
 
 
363
static void get_options(int *argc,char ***argv)
 
364
{
 
365
  int ho_error;
 
366
 
 
367
  my_progname= argv[0][0];
 
368
  if (isatty(fileno(stdout)))
 
369
    write_loop=1;
 
370
 
 
371
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
 
372
    exit(ho_error);
 
373
 
 
374
  if (!*argc)
 
375
  {
 
376
    usage();
 
377
    exit(1);
 
378
  }
 
379
  if (join_table)
 
380
  {
 
381
    backup=0;                                   /* Not needed */
 
382
    tmp_dir[0]=0;
 
383
  }
 
384
  return;
 
385
}
 
386
 
 
387
 
 
388
static MI_INFO *open_isam_file(char *name,int mode)
 
389
{
 
390
  MI_INFO *isam_file;
 
391
  MYISAM_SHARE *share;
 
392
 
 
393
  if (!(isam_file=mi_open(name,mode,
 
394
                          (opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
 
395
                           HA_OPEN_ABORT_IF_LOCKED))))
 
396
  {
 
397
    VOID(fprintf(stderr, "%s gave error %d on open\n", name, my_errno));
 
398
    return(0);
 
399
  }
 
400
  share=isam_file->s;
 
401
  if (share->options & HA_OPTION_COMPRESS_RECORD && !join_table)
 
402
  {
 
403
    if (!force_pack)
 
404
    {
 
405
      VOID(fprintf(stderr, "%s is already compressed\n", name));
 
406
      VOID(mi_close(isam_file));
 
407
      return(0);
 
408
    }
 
409
    if (verbose)
 
410
      puts("Recompressing already compressed table");
 
411
    share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
 
412
  }
 
413
  if (! force_pack && share->state.state.records != 0 &&
 
414
      (share->state.state.records <= 1 ||
 
415
       share->state.state.data_file_length < 1024))
 
416
  {
 
417
    VOID(fprintf(stderr, "%s is too small to compress\n", name));
 
418
    VOID(mi_close(isam_file));
 
419
    return(0);
 
420
  }
 
421
  VOID(mi_lock_database(isam_file,F_WRLCK));
 
422
  return(isam_file);
 
423
}
 
424
 
 
425
 
 
426
static my_bool open_isam_files(PACK_MRG_INFO *mrg, char **names, uint count)
 
427
{
 
428
  uint i,j;
 
429
  mrg->count=0;
 
430
  mrg->current=0;
 
431
  mrg->file=(MI_INFO**) my_malloc(sizeof(MI_INFO*)*count,MYF(MY_FAE));
 
432
  mrg->free_file=1;
 
433
  mrg->src_file_has_indexes_disabled= 0;
 
434
  for (i=0; i < count ; i++)
 
435
  {
 
436
    if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY)))
 
437
      goto error;
 
438
 
 
439
    mrg->src_file_has_indexes_disabled|=
 
440
      ! mi_is_all_keys_active(mrg->file[i]->s->state.key_map,
 
441
                              mrg->file[i]->s->base.keys);
 
442
  }
 
443
  /* Check that files are identical */
 
444
  for (j=0 ; j < count-1 ; j++)
 
445
  {
 
446
    MI_COLUMNDEF *m1,*m2,*end;
 
447
    if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
 
448
        mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
 
449
      goto diff_file;
 
450
    m1=mrg->file[j]->s->rec;
 
451
    end=m1+mrg->file[j]->s->base.fields;
 
452
    m2=mrg->file[j+1]->s->rec;
 
453
    for ( ; m1 != end ; m1++,m2++)
 
454
    {
 
455
      if (m1->type != m2->type || m1->length != m2->length)
 
456
        goto diff_file;
 
457
    }
 
458
  }
 
459
  mrg->count=count;
 
460
  return 0;
 
461
 
 
462
 diff_file:
 
463
  VOID(fprintf(stderr, "%s: Tables '%s' and '%s' are not identical\n",
 
464
               my_progname, names[j], names[j+1]));
 
465
 error:
 
466
  while (i--)
 
467
    mi_close(mrg->file[i]);
 
468
  my_free((uchar*) mrg->file,MYF(0));
 
469
  return 1;
 
470
}
 
471
 
 
472
 
 
473
static int compress(PACK_MRG_INFO *mrg,char *result_table)
 
474
{
 
475
  int error;
 
476
  File new_file,join_isam_file;
 
477
  MI_INFO *isam_file;
 
478
  MYISAM_SHARE *share;
 
479
  char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
 
480
  uint i,header_length,fields,trees,used_trees;
 
481
  my_off_t old_length,new_length,tot_elements;
 
482
  HUFF_COUNTS *huff_counts;
 
483
  HUFF_TREE *huff_trees;
 
484
 
 
485
  isam_file=mrg->file[0];                       /* Take this as an example */
 
486
  share=isam_file->s;
 
487
  new_file=join_isam_file= -1;
 
488
  trees=fields=0;
 
489
  huff_trees=0;
 
490
  huff_counts=0;
 
491
 
 
492
  /* Create temporary or join file */
 
493
 
 
494
  if (backup)
 
495
    VOID(fn_format(org_name,isam_file->filename,"",MI_NAME_DEXT,2));
 
496
  else
 
497
    VOID(fn_format(org_name,isam_file->filename,"",MI_NAME_DEXT,2+4+16));
 
498
  if (!test_only && result_table)
 
499
  {
 
500
    /* Make a new indexfile based on first file in list */
 
501
    uint length;
 
502
    uchar *buff;
 
503
    strmov(org_name,result_table);              /* Fix error messages */
 
504
    VOID(fn_format(new_name,result_table,"",MI_NAME_IEXT,2));
 
505
    if ((join_isam_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
 
506
        < 0)
 
507
      goto err;
 
508
    length=(uint) share->base.keystart;
 
509
    if (!(buff= (uchar*) my_malloc(length,MYF(MY_WME))))
 
510
      goto err;
 
511
    if (my_pread(share->kfile,buff,length,0L,MYF(MY_WME | MY_NABP)) ||
 
512
        my_write(join_isam_file,buff,length,
 
513
                 MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
 
514
    {
 
515
      my_free(buff,MYF(0));
 
516
      goto err;
 
517
    }
 
518
    my_free(buff,MYF(0));
 
519
    VOID(fn_format(new_name,result_table,"",MI_NAME_DEXT,2));
 
520
  }
 
521
  else if (!tmp_dir[0])
 
522
    VOID(make_new_name(new_name,org_name));
 
523
  else
 
524
    VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
 
525
  if (!test_only &&
 
526
      (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
 
527
    goto err;
 
528
 
 
529
  /* Start calculating statistics */
 
530
 
 
531
  mrg->records=0;
 
532
  for (i=0 ; i < mrg->count ; i++)
 
533
    mrg->records+=mrg->file[i]->s->state.state.records;
 
534
 
 
535
  if (write_loop || verbose)
 
536
  {
 
537
    VOID(printf("Compressing %s: (%lu records)\n",
 
538
                result_table ? new_name : org_name, (ulong) mrg->records));
 
539
  }
 
540
  trees=fields=share->base.fields;
 
541
  huff_counts=init_huff_count(isam_file,mrg->records);
 
542
  QUICK_SAFEMALLOC;
 
543
 
 
544
  /*
 
545
    Read the whole data file(s) for statistics.
 
546
  */
 
547
  if (write_loop || verbose)
 
548
    VOID(printf("- Calculating statistics\n"));
 
549
  if (get_statistic(mrg,huff_counts))
 
550
    goto err;
 
551
  NORMAL_SAFEMALLOC;
 
552
  old_length=0;
 
553
  for (i=0; i < mrg->count ; i++)
 
554
    old_length+= (mrg->file[i]->s->state.state.data_file_length -
 
555
                  mrg->file[i]->s->state.state.empty);
 
556
 
 
557
  /*
 
558
    Create a global priority queue in preparation for making 
 
559
    temporary Huffman trees.
 
560
  */
 
561
  if (init_queue(&queue,256,0,0,compare_huff_elements,0))
 
562
    goto err;
 
563
 
 
564
  /*
 
565
    Check each column if we should use pre-space-compress, end-space-
 
566
    compress, empty-field-compress or zero-field-compress.
 
567
  */
 
568
  check_counts(huff_counts,fields,mrg->records);
 
569
 
 
570
  /*
 
571
    Build a Huffman tree for each column.
 
572
  */
 
573
  huff_trees=make_huff_trees(huff_counts,trees);
 
574
 
 
575
  /*
 
576
    If the packed lengths of combined columns is less then the sum of
 
577
    the non-combined columns, then create common Huffman trees for them.
 
578
    We do this only for byte compressed columns, not for distinct values
 
579
    compressed columns.
 
580
  */
 
581
  if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
 
582
    goto err;
 
583
 
 
584
  /*
 
585
    Assign codes to all byte or column values.
 
586
  */
 
587
  if (make_huff_decode_table(huff_trees,fields))
 
588
    goto err;
 
589
 
 
590
  /* Prepare a file buffer. */
 
591
  init_file_buffer(new_file,0);
 
592
 
 
593
  /*
 
594
    Reserve space in the target file for the fixed compressed file header.
 
595
  */
 
596
  file_buffer.pos_in_file=HEAD_LENGTH;
 
597
  if (! test_only)
 
598
    VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
 
599
 
 
600
  /*
 
601
    Write field infos: field type, pack type, length bits, tree number.
 
602
  */
 
603
  write_field_info(huff_counts,fields,used_trees);
 
604
 
 
605
  /*
 
606
    Write decode trees.
 
607
  */
 
608
  if (!(tot_elements=write_huff_tree(huff_trees,trees)))
 
609
    goto err;
 
610
 
 
611
  /*
 
612
    Calculate the total length of the compression info header.
 
613
    This includes the fixed compressed file header, the column compression
 
614
    type descriptions, and the decode trees.
 
615
  */
 
616
  header_length=(uint) file_buffer.pos_in_file+
 
617
    (uint) (file_buffer.pos-file_buffer.buffer);
 
618
 
 
619
  /*
 
620
    Compress the source file into the target file.
 
621
  */
 
622
  if (write_loop || verbose)
 
623
    VOID(printf("- Compressing file\n"));
 
624
  error=compress_isam_file(mrg,huff_counts);
 
625
  new_length=file_buffer.pos_in_file;
 
626
  if (!error && !test_only)
 
627
  {
 
628
    uchar buff[MEMMAP_EXTRA_MARGIN];            /* End marginal for memmap */
 
629
    bzero(buff,sizeof(buff));
 
630
    error=my_write(file_buffer.file,buff,sizeof(buff),
 
631
                   MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
 
632
  }
 
633
 
 
634
  /*
 
635
    Write the fixed compressed file header.
 
636
  */
 
637
  if (!error)
 
638
    error=write_header(mrg,header_length,used_trees,tot_elements,
 
639
                       new_length);
 
640
 
 
641
  /* Flush the file buffer. */
 
642
  end_file_buffer();
 
643
 
 
644
  /* Display statistics. */
 
645
  if (verbose && mrg->records)
 
646
    VOID(printf("Min record length: %6d   Max length: %6d   "
 
647
                "Mean total length: %6ld\n", mrg->min_pack_length,
 
648
                mrg->max_pack_length, (ulong) (new_length/mrg->records)));
 
649
 
 
650
  /* Close source and target file. */
 
651
  if (!test_only)
 
652
  {
 
653
    error|=my_close(new_file,MYF(MY_WME));
 
654
    if (!result_table)
 
655
    {
 
656
      error|=my_close(isam_file->dfile,MYF(MY_WME));
 
657
      isam_file->dfile= -1;             /* Tell mi_close file is closed */
 
658
    }
 
659
  }
 
660
 
 
661
  /* Cleanup. */
 
662
  free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
 
663
  if (! test_only && ! error)
 
664
  {
 
665
    if (result_table)
 
666
    {
 
667
      error=save_state_mrg(join_isam_file,mrg,new_length,glob_crc);
 
668
    }
 
669
    else
 
670
    {
 
671
      if (backup)
 
672
      {
 
673
        if (my_rename(org_name,make_old_name(temp_name,isam_file->filename),
 
674
                      MYF(MY_WME)))
 
675
          error=1;
 
676
        else
 
677
        {
 
678
          if (tmp_dir[0])
 
679
            error=my_copy(new_name,org_name,MYF(MY_WME));
 
680
          else
 
681
            error=my_rename(new_name,org_name,MYF(MY_WME));
 
682
          if (!error)
 
683
          {
 
684
            VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
 
685
            if (tmp_dir[0])
 
686
              VOID(my_delete(new_name,MYF(MY_WME)));
 
687
          }
 
688
        }
 
689
      }
 
690
      else
 
691
      {
 
692
        if (tmp_dir[0])
 
693
        {
 
694
          error=my_copy(new_name,org_name,
 
695
                        MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_COPYTIME));
 
696
          if (!error)
 
697
            VOID(my_delete(new_name,MYF(MY_WME)));
 
698
        }
 
699
        else
 
700
          error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
 
701
      }
 
702
      if (! error)
 
703
        error=save_state(isam_file,mrg,new_length,glob_crc);
 
704
    }
 
705
  }
 
706
  error|=mrg_close(mrg);
 
707
  if (join_isam_file >= 0)
 
708
    error|=my_close(join_isam_file,MYF(MY_WME));
 
709
  if (error)
 
710
  {
 
711
    VOID(fprintf(stderr, "Aborting: %s is not compressed\n", org_name));
 
712
    VOID(my_delete(new_name,MYF(MY_WME)));
 
713
    return(-1);
 
714
  }
 
715
  if (write_loop || verbose)
 
716
  {
 
717
    if (old_length)
 
718
      VOID(printf("%.4g%%     \n",
 
719
                  (((int64_t) (old_length - new_length)) * 100.0 /
 
720
                   (int64_t) old_length)));
 
721
    else
 
722
      puts("Empty file saved in compressed format");
 
723
  }
 
724
  return(0);
 
725
 
 
726
 err:
 
727
  free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
 
728
  if (new_file >= 0)
 
729
    VOID(my_close(new_file,MYF(0)));
 
730
  if (join_isam_file >= 0)
 
731
    VOID(my_close(join_isam_file,MYF(0)));
 
732
  mrg_close(mrg);
 
733
  VOID(fprintf(stderr, "Aborted: %s is not compressed\n", org_name));
 
734
  return(-1);
 
735
}
 
736
 
 
737
        /* Init a huff_count-struct for each field and init it */
 
738
 
 
739
static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records)
 
740
{
 
741
  register uint i;
 
742
  register HUFF_COUNTS *count;
 
743
  if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*
 
744
                                        sizeof(HUFF_COUNTS),
 
745
                                        MYF(MY_ZEROFILL | MY_WME))))
 
746
  {
 
747
    for (i=0 ; i < info->s->base.fields ; i++)
 
748
    {
 
749
      enum en_fieldtype type;
 
750
      count[i].field_length=info->s->rec[i].length;
 
751
      type= count[i].field_type= (enum en_fieldtype) info->s->rec[i].type;
 
752
      if (type == FIELD_INTERVALL ||
 
753
          type == FIELD_CONSTANT ||
 
754
          type == FIELD_ZERO)
 
755
        type = FIELD_NORMAL;
 
756
      if (count[i].field_length <= 8 &&
 
757
          (type == FIELD_NORMAL ||
 
758
           type == FIELD_SKIP_ZERO))
 
759
        count[i].max_zero_fill= count[i].field_length;
 
760
      /*
 
761
        For every column initialize a tree, which is used to detect distinct
 
762
        column values. 'int_tree' works together with 'tree_buff' and
 
763
        'tree_pos'. It's keys are implemented by pointers into 'tree_buff'.
 
764
        This is accomplished by '-1' as the element size.
 
765
      */
 
766
      init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0, NULL,
 
767
                NULL);
 
768
      if (records && type != FIELD_BLOB && type != FIELD_VARCHAR)
 
769
        count[i].tree_pos=count[i].tree_buff =
 
770
          my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
 
771
                    MYF(MY_WME));
 
772
    }
 
773
  }
 
774
  return count;
 
775
}
 
776
 
 
777
 
 
778
        /* Free memory used by counts and trees */
 
779
 
 
780
static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees,
 
781
                                           HUFF_COUNTS *huff_counts,
 
782
                                           uint fields)
 
783
{
 
784
  register uint i;
 
785
 
 
786
  if (huff_trees)
 
787
  {
 
788
    for (i=0 ; i < trees ; i++)
 
789
    {
 
790
      if (huff_trees[i].element_buffer)
 
791
        my_free((uchar*) huff_trees[i].element_buffer,MYF(0));
 
792
      if (huff_trees[i].code)
 
793
        my_free((uchar*) huff_trees[i].code,MYF(0));
 
794
    }
 
795
    my_free((uchar*) huff_trees,MYF(0));
 
796
  }
 
797
  if (huff_counts)
 
798
  {
 
799
    for (i=0 ; i < fields ; i++)
 
800
    {
 
801
      if (huff_counts[i].tree_buff)
 
802
      {
 
803
        my_free((uchar*) huff_counts[i].tree_buff,MYF(0));
 
804
        delete_tree(&huff_counts[i].int_tree);
 
805
      }
 
806
    }
 
807
    my_free((uchar*) huff_counts,MYF(0));
 
808
  }
 
809
  delete_queue(&queue);         /* This is safe to free */
 
810
  return;
 
811
}
 
812
 
 
813
        /* Read through old file and gather some statistics */
 
814
 
 
815
static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
 
816
{
 
817
  int error;
 
818
  uint length;
 
819
  ulong reclength,max_blob_length;
 
820
  uchar *record,*pos,*next_pos,*end_pos,*start_pos;
 
821
  ha_rows record_count;
 
822
  my_bool static_row_size;
 
823
  HUFF_COUNTS *count,*end_count;
 
824
  TREE_ELEMENT *element;
 
825
 
 
826
  reclength=mrg->file[0]->s->base.reclength;
 
827
  record=(uchar*) my_alloca(reclength);
 
828
  end_count=huff_counts+mrg->file[0]->s->base.fields;
 
829
  record_count=0; glob_crc=0;
 
830
  max_blob_length=0;
 
831
 
 
832
  /* Check how to calculate checksum */
 
833
  static_row_size=1;
 
834
  for (count=huff_counts ; count < end_count ; count++)
 
835
  {
 
836
    if (count->field_type == FIELD_BLOB ||
 
837
        count->field_type == FIELD_VARCHAR)
 
838
    {
 
839
      static_row_size=0;
 
840
      break;
 
841
    }
 
842
  }
 
843
 
 
844
  mrg_reset(mrg);
 
845
  while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
 
846
  {
 
847
    ulong tot_blob_length=0;
 
848
    if (! error)
 
849
    {
 
850
      /* glob_crc is a checksum over all bytes of all records. */
 
851
      if (static_row_size)
 
852
        glob_crc+=mi_static_checksum(mrg->file[0],record);
 
853
      else
 
854
        glob_crc+=mi_checksum(mrg->file[0],record);
 
855
 
 
856
      /* Count the incidence of values separately for every column. */
 
857
      for (pos=record,count=huff_counts ;
 
858
           count < end_count ;
 
859
           count++,
 
860
           pos=next_pos)
 
861
      {
 
862
        next_pos=end_pos=(start_pos=pos)+count->field_length;
 
863
 
 
864
        /*
 
865
          Put the whole column value in a tree if there is room for it.
 
866
          'int_tree' is used to quickly check for duplicate values.
 
867
          'tree_buff' collects as many distinct column values as
 
868
          possible. If the field length is > 1, it is tree_buff_length,
 
869
          else 2 bytes. Each value is 'field_length' bytes big. If there
 
870
          are more distinct column values than fit into the buffer, we
 
871
          give up with this tree. BLOBs and VARCHARs do not have a
 
872
          tree_buff as it can only be used with fixed length columns.
 
873
          For the special case of field length == 1, we handle only the
 
874
          case that there is only one distinct value in the table(s).
 
875
          Otherwise, we can have a maximum of 256 distinct values. This
 
876
          is then handled by the normal Huffman tree build.
 
877
 
 
878
          Another limit for collecting distinct column values is the
 
879
          number of values itself. Since we would need to build a
 
880
          Huffman tree for the values, we are limited by the 'IS_OFFSET'
 
881
          constant. This constant expresses a bit which is used to
 
882
          determine if a tree element holds a final value or an offset
 
883
          to a child element. Hence, all values and offsets need to be
 
884
          smaller than 'IS_OFFSET'. A tree element is implemented with
 
885
          two integer values, one for the left branch and one for the
 
886
          right branch. For the extreme case that the first element
 
887
          points to the last element, the number of integers in the tree
 
888
          must be less or equal to IS_OFFSET. So the number of elements
 
889
          must be less or equal to IS_OFFSET / 2.
 
890
 
 
891
          WARNING: At first, we insert a pointer into the record buffer
 
892
          as the key for the tree. If we got a new distinct value, which
 
893
          is really inserted into the tree, instead of being counted
 
894
          only, we will copy the column value from the record buffer to
 
895
          'tree_buff' and adjust the key pointer of the tree accordingly.
 
896
        */
 
897
        if (count->tree_buff)
 
898
        {
 
899
          global_count=count;
 
900
          if (!(element=tree_insert(&count->int_tree,pos, 0, 
 
901
                                    count->int_tree.custom_arg)) ||
 
902
              (element->count == 1 &&
 
903
               (count->tree_buff + tree_buff_length <
 
904
                count->tree_pos + count->field_length)) ||
 
905
              (count->int_tree.elements_in_tree > IS_OFFSET / 2) ||
 
906
              (count->field_length == 1 &&
 
907
               count->int_tree.elements_in_tree > 1))
 
908
          {
 
909
            delete_tree(&count->int_tree);
 
910
            my_free(count->tree_buff,MYF(0));
 
911
            count->tree_buff=0;
 
912
          }
 
913
          else
 
914
          {
 
915
            /*
 
916
              If tree_insert() succeeds, it either creates a new element
 
917
              or increments the counter of an existing element.
 
918
            */
 
919
            if (element->count == 1)
 
920
            {
 
921
              /* Copy the new column value into 'tree_buff'. */
 
922
              memcpy(count->tree_pos,pos,(size_t) count->field_length);
 
923
              /* Adjust the key pointer in the tree. */
 
924
              tree_set_pointer(element,count->tree_pos);
 
925
              /* Point behind the last column value so far. */
 
926
              count->tree_pos+=count->field_length;
 
927
            }
 
928
          }
 
929
        }
 
930
 
 
931
        /* Save character counters and space-counts and zero-field-counts */
 
932
        if (count->field_type == FIELD_NORMAL ||
 
933
            count->field_type == FIELD_SKIP_ENDSPACE)
 
934
        {
 
935
          /* Ignore trailing space. */
 
936
          for ( ; end_pos > pos ; end_pos--)
 
937
            if (end_pos[-1] != ' ')
 
938
              break;
 
939
          /* Empty fields are just counted. Go to the next record. */
 
940
          if (end_pos == pos)
 
941
          {
 
942
            count->empty_fields++;
 
943
            count->max_zero_fill=0;
 
944
            continue;
 
945
          }
 
946
          /*
 
947
            Count the total of all trailing spaces and the number of
 
948
            short trailing spaces. Remember the longest trailing space.
 
949
          */
 
950
          length= (uint) (next_pos-end_pos);
 
951
          count->tot_end_space+=length;
 
952
          if (length < 8)
 
953
            count->end_space[length]++;
 
954
          if (count->max_end_space < length)
 
955
            count->max_end_space = length;
 
956
        }
 
957
 
 
958
        if (count->field_type == FIELD_NORMAL ||
 
959
            count->field_type == FIELD_SKIP_PRESPACE)
 
960
        {
 
961
          /* Ignore leading space. */
 
962
          for (pos=start_pos; pos < end_pos ; pos++)
 
963
            if (pos[0] != ' ')
 
964
              break;
 
965
          /* Empty fields are just counted. Go to the next record. */
 
966
          if (end_pos == pos)
 
967
          {
 
968
            count->empty_fields++;
 
969
            count->max_zero_fill=0;
 
970
            continue;
 
971
          }
 
972
          /*
 
973
            Count the total of all leading spaces and the number of
 
974
            short leading spaces. Remember the longest leading space.
 
975
          */
 
976
          length= (uint) (pos-start_pos);
 
977
          count->tot_pre_space+=length;
 
978
          if (length < 8)
 
979
            count->pre_space[length]++;
 
980
          if (count->max_pre_space < length)
 
981
            count->max_pre_space = length;
 
982
        }
 
983
 
 
984
        /* Calculate pos, end_pos, and max_length for variable length fields. */
 
985
        if (count->field_type == FIELD_BLOB)
 
986
        {
 
987
          uint field_length=count->field_length -portable_sizeof_char_ptr;
 
988
          ulong blob_length= _mi_calc_blob_length(field_length, start_pos);
 
989
          memcpy_fixed((char*) &pos,  start_pos+field_length,sizeof(char*));
 
990
          end_pos=pos+blob_length;
 
991
          tot_blob_length+=blob_length;
 
992
          set_if_bigger(count->max_length,blob_length);
 
993
        }
 
994
        else if (count->field_type == FIELD_VARCHAR)
 
995
        {
 
996
          uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
 
997
          length= (pack_length == 1 ? (uint) *(uchar*) start_pos :
 
998
                   uint2korr(start_pos));
 
999
          pos= start_pos+pack_length;
 
1000
          end_pos= pos+length;
 
1001
          set_if_bigger(count->max_length,length);
 
1002
        }
 
1003
 
 
1004
        /* Evaluate 'max_zero_fill' for short fields. */
 
1005
        if (count->field_length <= 8 &&
 
1006
            (count->field_type == FIELD_NORMAL ||
 
1007
             count->field_type == FIELD_SKIP_ZERO))
 
1008
        {
 
1009
          uint i;
 
1010
          /* Zero fields are just counted. Go to the next record. */
 
1011
          if (!memcmp((uchar*) start_pos,zero_string,count->field_length))
 
1012
          {
 
1013
            count->zero_fields++;
 
1014
            continue;
 
1015
          }
 
1016
          /*
 
1017
            max_zero_fill starts with field_length. It is decreased every
 
1018
            time a shorter "zero trailer" is found. It is set to zero when
 
1019
            an empty field is found (see above). This suggests that the
 
1020
            variable should be called 'min_zero_fill'.
 
1021
          */
 
1022
          for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ;
 
1023
               i++) ;
 
1024
          if (i < count->max_zero_fill)
 
1025
            count->max_zero_fill=i;
 
1026
        }
 
1027
 
 
1028
        /* Ignore zero fields and check fields. */
 
1029
        if (count->field_type == FIELD_ZERO ||
 
1030
            count->field_type == FIELD_CHECK)
 
1031
          continue;
 
1032
 
 
1033
        /*
 
1034
          Count the incidence of every byte value in the
 
1035
          significant field value.
 
1036
        */
 
1037
        for ( ; pos < end_pos ; pos++)
 
1038
          count->counts[(uchar) *pos]++;
 
1039
 
 
1040
        /* Step to next field. */
 
1041
      }
 
1042
 
 
1043
      if (tot_blob_length > max_blob_length)
 
1044
        max_blob_length=tot_blob_length;
 
1045
      record_count++;
 
1046
      if (write_loop && record_count % WRITE_COUNT == 0)
 
1047
      {
 
1048
        VOID(printf("%lu\r", (ulong) record_count));
 
1049
        VOID(fflush(stdout));
 
1050
      }
 
1051
    }
 
1052
    else if (error != HA_ERR_RECORD_DELETED)
 
1053
    {
 
1054
      VOID(fprintf(stderr, "Got error %d while reading rows", error));
 
1055
      break;
 
1056
    }
 
1057
 
 
1058
    /* Step to next record. */
 
1059
  }
 
1060
  if (write_loop)
 
1061
  {
 
1062
    VOID(printf("            \r"));
 
1063
    VOID(fflush(stdout));
 
1064
  }
 
1065
 
 
1066
  if (verbose >= 2)
 
1067
    VOID(printf("Found the following number of incidents "
 
1068
                "of the byte codes:\n"));
 
1069
  for (count= huff_counts ; count < end_count; count++)
 
1070
  {
 
1071
    uint      idx;
 
1072
    my_off_t  total_count;
 
1073
    char      llbuf[32];
 
1074
 
 
1075
    if (verbose >= 2)
 
1076
      VOID(printf("column: %3u\n", (uint) (count - huff_counts + 1)));
 
1077
    if (count->tree_buff)
 
1078
    {
 
1079
      if (verbose >= 2)
 
1080
        VOID(printf("number of distinct values: %u\n",
 
1081
                    (uint) ((count->tree_pos - count->tree_buff) /
 
1082
                            count->field_length)));
 
1083
    }
 
1084
    total_count= 0;
 
1085
    for (idx= 0; idx < 256; idx++)
 
1086
    {
 
1087
      if (count->counts[idx])
 
1088
      {
 
1089
        total_count+= count->counts[idx];
 
1090
        if (verbose >= 2)
 
1091
          VOID(printf("counts[0x%02x]: %12s\n", idx,
 
1092
                      llstr((int64_t) count->counts[idx], llbuf)));
 
1093
      }
 
1094
    }
 
1095
    if ((verbose >= 2) && total_count)
 
1096
    {
 
1097
      VOID(printf("total:        %12s\n",
 
1098
                  llstr((int64_t) total_count, llbuf)));
 
1099
    }
 
1100
  }
 
1101
 
 
1102
  mrg->records=record_count;
 
1103
  mrg->max_blob_length=max_blob_length;
 
1104
  my_afree((uchar*) record);
 
1105
  return(error != HA_ERR_END_OF_FILE);
 
1106
}
 
1107
 
 
1108
static int compare_huff_elements(void *not_used __attribute__((unused)),
 
1109
                                 uchar *a, uchar *b)
 
1110
{
 
1111
  return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
 
1112
    (*((my_off_t*) a) == *((my_off_t*) b)  ? 0 : 1);
 
1113
}
 
1114
 
 
1115
        /* Check each tree if we should use pre-space-compress, end-space-
 
1116
           compress, empty-field-compress or zero-field-compress */
 
1117
 
 
1118
static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
 
1119
                         my_off_t records)
 
1120
{
 
1121
  uint space_fields,fill_zero_fields,field_count[(int) FIELD_enum_val_count];
 
1122
  my_off_t old_length,new_length,length;
 
1123
 
 
1124
  bzero((uchar*) field_count,sizeof(field_count));
 
1125
  space_fields=fill_zero_fields=0;
 
1126
 
 
1127
  for (; trees-- ; huff_counts++)
 
1128
  {
 
1129
    if (huff_counts->field_type == FIELD_BLOB)
 
1130
    {
 
1131
      huff_counts->length_bits=max_bit(huff_counts->max_length);
 
1132
      goto found_pack;
 
1133
    }
 
1134
    else if (huff_counts->field_type == FIELD_VARCHAR)
 
1135
    {
 
1136
      huff_counts->length_bits=max_bit(huff_counts->max_length);
 
1137
      goto found_pack;
 
1138
    }
 
1139
    else if (huff_counts->field_type == FIELD_CHECK)
 
1140
    {
 
1141
      huff_counts->bytes_packed=0;
 
1142
      huff_counts->counts[0]=0;
 
1143
      goto found_pack;
 
1144
    }
 
1145
 
 
1146
    huff_counts->field_type=FIELD_NORMAL;
 
1147
    huff_counts->pack_type=0;
 
1148
 
 
1149
    /* Check for zero-filled records (in this column), or zero records. */
 
1150
    if (huff_counts->zero_fields || ! records)
 
1151
    {
 
1152
      my_off_t old_space_count;
 
1153
      /*
 
1154
        If there are only zero filled records (in this column),
 
1155
        or no records at all, we are done.
 
1156
      */
 
1157
      if (huff_counts->zero_fields == records)
 
1158
      {
 
1159
        huff_counts->field_type= FIELD_ZERO;
 
1160
        huff_counts->bytes_packed=0;
 
1161
        huff_counts->counts[0]=0;
 
1162
        goto found_pack;
 
1163
      }
 
1164
      /* Remeber the number of significant spaces. */
 
1165
      old_space_count=huff_counts->counts[' '];
 
1166
      /* Add all leading and trailing spaces. */
 
1167
      huff_counts->counts[' ']+= (huff_counts->tot_end_space +
 
1168
                                  huff_counts->tot_pre_space +
 
1169
                                  huff_counts->empty_fields *
 
1170
                                  huff_counts->field_length);
 
1171
      /* Check, what the compressed length of this would be. */
 
1172
      old_length=calc_packed_length(huff_counts,0)+records/8;
 
1173
      /* Get the number of zero bytes. */
 
1174
      length=huff_counts->zero_fields*huff_counts->field_length;
 
1175
      /* Add it to the counts. */
 
1176
      huff_counts->counts[0]+=length;
 
1177
      /* Check, what the compressed length of this would be. */
 
1178
      new_length=calc_packed_length(huff_counts,0);
 
1179
      /* If the compression without the zeroes would be shorter, we are done. */
 
1180
      if (old_length < new_length && huff_counts->field_length > 1)
 
1181
      {
 
1182
        huff_counts->field_type=FIELD_SKIP_ZERO;
 
1183
        huff_counts->counts[0]-=length;
 
1184
        huff_counts->bytes_packed=old_length- records/8;
 
1185
        goto found_pack;
 
1186
      }
 
1187
      /* Remove the insignificant spaces, but keep the zeroes. */
 
1188
      huff_counts->counts[' ']=old_space_count;
 
1189
    }
 
1190
    /* Check, what the compressed length of this column would be. */
 
1191
    huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
 
1192
 
 
1193
    /*
 
1194
      If there are enough empty records (in this column),
 
1195
      treating them specially may pay off.
 
1196
    */
 
1197
    if (huff_counts->empty_fields)
 
1198
    {
 
1199
      if (huff_counts->field_length > 2 &&
 
1200
          huff_counts->empty_fields + (records - huff_counts->empty_fields)*
 
1201
          (1+max_bit(max(huff_counts->max_pre_space,
 
1202
                         huff_counts->max_end_space))) <
 
1203
          records * max_bit(huff_counts->field_length))
 
1204
      {
 
1205
        huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
 
1206
      }
 
1207
      else
 
1208
      {
 
1209
        length=huff_counts->empty_fields*huff_counts->field_length;
 
1210
        if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
 
1211
        {
 
1212
          huff_counts->tot_end_space+=length;
 
1213
          huff_counts->max_end_space=huff_counts->field_length;
 
1214
          if (huff_counts->field_length < 8)
 
1215
            huff_counts->end_space[huff_counts->field_length]+=
 
1216
              huff_counts->empty_fields;
 
1217
        }
 
1218
        if (huff_counts->tot_pre_space)
 
1219
        {
 
1220
          huff_counts->tot_pre_space+=length;
 
1221
          huff_counts->max_pre_space=huff_counts->field_length;
 
1222
          if (huff_counts->field_length < 8)
 
1223
            huff_counts->pre_space[huff_counts->field_length]+=
 
1224
              huff_counts->empty_fields;
 
1225
        }
 
1226
      }
 
1227
    }
 
1228
 
 
1229
    /*
 
1230
      If there are enough trailing spaces (in this column),
 
1231
      treating them specially may pay off.
 
1232
    */
 
1233
    if (huff_counts->tot_end_space)
 
1234
    {
 
1235
      huff_counts->counts[' ']+=huff_counts->tot_pre_space;
 
1236
      if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
 
1237
                              huff_counts->end_space,
 
1238
                              huff_counts->tot_end_space,FIELD_SKIP_ENDSPACE))
 
1239
        goto found_pack;
 
1240
      huff_counts->counts[' ']-=huff_counts->tot_pre_space;
 
1241
    }
 
1242
 
 
1243
    /*
 
1244
      If there are enough leading spaces (in this column),
 
1245
      treating them specially may pay off.
 
1246
    */
 
1247
    if (huff_counts->tot_pre_space)
 
1248
    {
 
1249
      if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
 
1250
                              huff_counts->pre_space,
 
1251
                              huff_counts->tot_pre_space,FIELD_SKIP_PRESPACE))
 
1252
        goto found_pack;
 
1253
    }
 
1254
 
 
1255
  found_pack:                   /* Found field-packing */
 
1256
 
 
1257
    /* Test if we can use zero-fill */
 
1258
 
 
1259
    if (huff_counts->max_zero_fill &&
 
1260
        (huff_counts->field_type == FIELD_NORMAL ||
 
1261
         huff_counts->field_type == FIELD_SKIP_ZERO))
 
1262
    {
 
1263
      huff_counts->counts[0]-=huff_counts->max_zero_fill*
 
1264
        (huff_counts->field_type == FIELD_SKIP_ZERO ?
 
1265
         records - huff_counts->zero_fields : records);
 
1266
      huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
 
1267
      huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
 
1268
    }
 
1269
 
 
1270
    /* Test if intervall-field is better */
 
1271
 
 
1272
    if (huff_counts->tree_buff)
 
1273
    {
 
1274
      HUFF_TREE tree;
 
1275
 
 
1276
      tree.element_buffer=0;
 
1277
      if (!make_huff_tree(&tree,huff_counts) &&
 
1278
          tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
 
1279
      {
 
1280
        if (tree.elements == 1)
 
1281
          huff_counts->field_type=FIELD_CONSTANT;
 
1282
        else
 
1283
          huff_counts->field_type=FIELD_INTERVALL;
 
1284
        huff_counts->pack_type=0;
 
1285
      }
 
1286
      else
 
1287
      {
 
1288
        my_free((uchar*) huff_counts->tree_buff,MYF(0));
 
1289
        delete_tree(&huff_counts->int_tree);
 
1290
        huff_counts->tree_buff=0;
 
1291
      }
 
1292
      if (tree.element_buffer)
 
1293
        my_free((uchar*) tree.element_buffer,MYF(0));
 
1294
    }
 
1295
    if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
 
1296
      space_fields++;
 
1297
    if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
 
1298
      fill_zero_fields++;
 
1299
    field_count[huff_counts->field_type]++;
 
1300
  }
 
1301
  if (verbose)
 
1302
    VOID(printf("\nnormal:    %3d  empty-space:     %3d  "
 
1303
                "empty-zero:       %3d  empty-fill: %3d\n"
 
1304
                "pre-space: %3d  end-space:       %3d  "
 
1305
                "intervall-fields: %3d  zero:       %3d\n",
 
1306
                field_count[FIELD_NORMAL],space_fields,
 
1307
                field_count[FIELD_SKIP_ZERO],fill_zero_fields,
 
1308
                field_count[FIELD_SKIP_PRESPACE],
 
1309
                field_count[FIELD_SKIP_ENDSPACE],
 
1310
                field_count[FIELD_INTERVALL],
 
1311
                field_count[FIELD_ZERO]));
 
1312
  return;
 
1313
}
 
1314
 
 
1315
        /* Test if we can use space-compression and empty-field-compression */
 
1316
 
 
1317
static int
 
1318
test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
 
1319
                    uint max_space_length, my_off_t *space_counts,
 
1320
                    my_off_t tot_space_count, enum en_fieldtype field_type)
 
1321
{
 
1322
  int min_pos;
 
1323
  uint length_bits,i;
 
1324
  my_off_t space_count,min_space_count,min_pack,new_length,skip;
 
1325
 
 
1326
  length_bits=max_bit(max_space_length);
 
1327
 
 
1328
                /* Default no end_space-packing */
 
1329
  space_count=huff_counts->counts[(uint) ' '];
 
1330
  min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
 
1331
  min_pack=calc_packed_length(huff_counts,0);
 
1332
  min_pos= -2;
 
1333
  huff_counts->counts[(uint) ' ']=space_count;
 
1334
 
 
1335
        /* Test with allways space-count */
 
1336
  new_length=huff_counts->bytes_packed+length_bits*records/8;
 
1337
  if (new_length+1 < min_pack)
 
1338
  {
 
1339
    min_pos= -1;
 
1340
    min_pack=new_length;
 
1341
    min_space_count=space_count;
 
1342
  }
 
1343
        /* Test with length-flag */
 
1344
  for (skip=0L, i=0 ; i < 8 ; i++)
 
1345
  {
 
1346
    if (space_counts[i])
 
1347
    {
 
1348
      if (i)
 
1349
        huff_counts->counts[(uint) ' ']+=space_counts[i];
 
1350
      skip+=huff_counts->pre_space[i];
 
1351
      new_length=calc_packed_length(huff_counts,0)+
 
1352
        (records+(records-skip)*(1+length_bits))/8;
 
1353
      if (new_length < min_pack)
 
1354
      {
 
1355
        min_pos=(int) i;
 
1356
        min_pack=new_length;
 
1357
        min_space_count=huff_counts->counts[(uint) ' '];
 
1358
      }
 
1359
    }
 
1360
  }
 
1361
 
 
1362
  huff_counts->counts[(uint) ' ']=min_space_count;
 
1363
  huff_counts->bytes_packed=min_pack;
 
1364
  switch (min_pos) {
 
1365
  case -2:
 
1366
    return(0);                          /* No space-compress */
 
1367
  case -1:                              /* Always space-count */
 
1368
    huff_counts->field_type=field_type;
 
1369
    huff_counts->min_space=0;
 
1370
    huff_counts->length_bits=max_bit(max_space_length);
 
1371
    break;
 
1372
  default:
 
1373
    huff_counts->field_type=field_type;
 
1374
    huff_counts->min_space=(uint) min_pos;
 
1375
    huff_counts->pack_type|=PACK_TYPE_SELECTED;
 
1376
    huff_counts->length_bits=max_bit(max_space_length);
 
1377
    break;
 
1378
  }
 
1379
  return(1);                            /* Using space-compress */
 
1380
}
 
1381
 
 
1382
 
 
1383
        /* Make a huff_tree of each huff_count */
 
1384
 
 
1385
static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
 
1386
{
 
1387
  uint tree;
 
1388
  HUFF_TREE *huff_tree;
 
1389
 
 
1390
  if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
 
1391
                                         MYF(MY_WME | MY_ZEROFILL))))
 
1392
    return(0);
 
1393
 
 
1394
  for (tree=0 ; tree < trees ; tree++)
 
1395
  {
 
1396
    if (make_huff_tree(huff_tree+tree,huff_counts+tree))
 
1397
    {
 
1398
      while (tree--)
 
1399
        my_free((uchar*) huff_tree[tree].element_buffer,MYF(0));
 
1400
      my_free((uchar*) huff_tree,MYF(0));
 
1401
      return(0);
 
1402
    }
 
1403
  }
 
1404
  return(huff_tree);
 
1405
}
 
1406
 
 
1407
/*
 
1408
  Build a Huffman tree.
 
1409
 
 
1410
  SYNOPSIS
 
1411
    make_huff_tree()
 
1412
    huff_tree                   The Huffman tree.
 
1413
    huff_counts                 The counts.
 
1414
 
 
1415
  DESCRIPTION
 
1416
    Build a Huffman tree according to huff_counts->counts or
 
1417
    huff_counts->tree_buff. tree_buff, if non-NULL contains up to
 
1418
    tree_buff_length of distinct column values. In that case, whole
 
1419
    values can be Huffman encoded instead of single bytes.
 
1420
 
 
1421
  RETURN
 
1422
    0           OK
 
1423
    != 0        Error
 
1424
*/
 
1425
 
 
1426
static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
 
1427
{
 
1428
  uint i,found,bits_packed,first,last;
 
1429
  my_off_t bytes_packed;
 
1430
  HUFF_ELEMENT *a,*b,*new_huff_el;
 
1431
 
 
1432
  first=last=0;
 
1433
  if (huff_counts->tree_buff)
 
1434
  {
 
1435
    /* Calculate the number of distinct values in tree_buff. */
 
1436
    found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
 
1437
      huff_counts->field_length;
 
1438
    first=0; last=found-1;
 
1439
  }
 
1440
  else
 
1441
  {
 
1442
    /* Count the number of byte codes found in the column. */
 
1443
    for (i=found=0 ; i < 256 ; i++)
 
1444
    {
 
1445
      if (huff_counts->counts[i])
 
1446
      {
 
1447
        if (! found++)
 
1448
          first=i;
 
1449
        last=i;
 
1450
      }
 
1451
    }
 
1452
    if (found < 2)
 
1453
      found=2;
 
1454
  }
 
1455
 
 
1456
  /* When using 'tree_buff' we can have more that 256 values. */
 
1457
  if (queue.max_elements < found)
 
1458
  {
 
1459
    delete_queue(&queue);
 
1460
    if (init_queue(&queue,found,0,0,compare_huff_elements,0))
 
1461
      return -1;
 
1462
  }
 
1463
 
 
1464
  /* Allocate or reallocate an element buffer for the Huffman tree. */
 
1465
  if (!huff_tree->element_buffer)
 
1466
  {
 
1467
    if (!(huff_tree->element_buffer=
 
1468
         (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
 
1469
      return 1;
 
1470
  }
 
1471
  else
 
1472
  {
 
1473
    HUFF_ELEMENT *temp;
 
1474
    if (!(temp=
 
1475
          (HUFF_ELEMENT*) my_realloc((uchar*) huff_tree->element_buffer,
 
1476
                                     found*2*sizeof(HUFF_ELEMENT),
 
1477
                                     MYF(MY_WME))))
 
1478
      return 1;
 
1479
    huff_tree->element_buffer=temp;
 
1480
  }
 
1481
 
 
1482
  huff_counts->tree=huff_tree;
 
1483
  huff_tree->counts=huff_counts;
 
1484
  huff_tree->min_chr=first;
 
1485
  huff_tree->max_chr=last;
 
1486
  huff_tree->char_bits=max_bit(last-first);
 
1487
  huff_tree->offset_bits=max_bit(found-1)+1;
 
1488
 
 
1489
  if (huff_counts->tree_buff)
 
1490
  {
 
1491
    huff_tree->elements=0;
 
1492
    huff_tree->tree_pack_length=(1+15+16+5+5+
 
1493
                                 (huff_tree->char_bits+1)*found+
 
1494
                                 (huff_tree->offset_bits+1)*
 
1495
                                 (found-2)+7)/8 +
 
1496
                                   (uint) (huff_tree->counts->tree_pos-
 
1497
                                           huff_tree->counts->tree_buff);
 
1498
    /*
 
1499
      Put a HUFF_ELEMENT into the queue for every distinct column value.
 
1500
 
 
1501
      tree_walk() calls save_counts_in_queue() for every element in
 
1502
      'int_tree'. This takes elements from the target trees element
 
1503
      buffer and places references to them into the buffer of the
 
1504
      priority queue. We insert in column value order, but the order is
 
1505
      in fact irrelevant here. We will establish the correct order
 
1506
      later.
 
1507
    */
 
1508
    tree_walk(&huff_counts->int_tree,
 
1509
              (int (*)(void*, element_count,void*)) save_counts_in_queue,
 
1510
              (uchar*) huff_tree, left_root_right);
 
1511
  }
 
1512
  else
 
1513
  {
 
1514
    huff_tree->elements=found;
 
1515
    huff_tree->tree_pack_length=(9+9+5+5+
 
1516
                                 (huff_tree->char_bits+1)*found+
 
1517
                                 (huff_tree->offset_bits+1)*
 
1518
                                 (found-2)+7)/8;
 
1519
    /*
 
1520
      Put a HUFF_ELEMENT into the queue for every byte code found in the column.
 
1521
 
 
1522
      The elements are taken from the target trees element buffer.
 
1523
      Instead of using queue_insert(), we just place references to the
 
1524
      elements into the buffer of the priority queue. We insert in byte
 
1525
      value order, but the order is in fact irrelevant here. We will
 
1526
      establish the correct order later.
 
1527
    */
 
1528
    for (i=first, found=0 ; i <= last ; i++)
 
1529
    {
 
1530
      if (huff_counts->counts[i])
 
1531
      {
 
1532
        new_huff_el=huff_tree->element_buffer+(found++);
 
1533
        new_huff_el->count=huff_counts->counts[i];
 
1534
        new_huff_el->a.leaf.null=0;
 
1535
        new_huff_el->a.leaf.element_nr=i;
 
1536
        queue.root[found]=(uchar*) new_huff_el;
 
1537
      }
 
1538
    }
 
1539
    /*
 
1540
      If there is only a single byte value in this field in all records,
 
1541
      add a second element with zero incidence. This is required to enter
 
1542
      the loop, which builds the Huffman tree.
 
1543
    */
 
1544
    while (found < 2)
 
1545
    {
 
1546
      new_huff_el=huff_tree->element_buffer+(found++);
 
1547
      new_huff_el->count=0;
 
1548
      new_huff_el->a.leaf.null=0;
 
1549
      if (last)
 
1550
        new_huff_el->a.leaf.element_nr=huff_tree->min_chr=last-1;
 
1551
      else
 
1552
        new_huff_el->a.leaf.element_nr=huff_tree->max_chr=last+1;
 
1553
      queue.root[found]=(uchar*) new_huff_el;
 
1554
    }
 
1555
  }
 
1556
 
 
1557
  /* Make a queue from the queue buffer. */
 
1558
  queue.elements=found;
 
1559
 
 
1560
  /*
 
1561
    Make a priority queue from the queue. Construct its index so that we
 
1562
    have a partially ordered tree.
 
1563
  */
 
1564
  for (i=found/2 ; i > 0 ; i--)
 
1565
    _downheap(&queue,i);
 
1566
 
 
1567
  /* The Huffman algorithm. */
 
1568
  bytes_packed=0; bits_packed=0;
 
1569
  for (i=1 ; i < found ; i++)
 
1570
  {
 
1571
    /*
 
1572
      Pop the top element from the queue (the one with the least incidence).
 
1573
      Popping from a priority queue includes a re-ordering of the queue,
 
1574
      to get the next least incidence element to the top.
 
1575
    */
 
1576
    a=(HUFF_ELEMENT*) queue_remove(&queue,0);
 
1577
    /*
 
1578
      Copy the next least incidence element. The queue implementation
 
1579
      reserves root[0] for temporary purposes. root[1] is the top.
 
1580
    */
 
1581
    b=(HUFF_ELEMENT*) queue.root[1];
 
1582
    /* Get a new element from the element buffer. */
 
1583
    new_huff_el=huff_tree->element_buffer+found+i;
 
1584
    /* The new element gets the sum of the two least incidence elements. */
 
1585
    new_huff_el->count=a->count+b->count;
 
1586
    /*
 
1587
      The Huffman algorithm assigns another bit to the code for a byte
 
1588
      every time that bytes incidence is combined (directly or indirectly)
 
1589
      to a new element as one of the two least incidence elements.
 
1590
      This means that one more bit per incidence of that byte is required
 
1591
      in the resulting file. So we add the new combined incidence as the
 
1592
      number of bits by which the result grows.
 
1593
    */
 
1594
    bits_packed+=(uint) (new_huff_el->count & 7);
 
1595
    bytes_packed+=new_huff_el->count/8;
 
1596
    /* The new element points to its children, lesser in left.  */
 
1597
    new_huff_el->a.nod.left=a;
 
1598
    new_huff_el->a.nod.right=b;
 
1599
    /*
 
1600
      Replace the copied top element by the new element and re-order the
 
1601
      queue.
 
1602
    */
 
1603
    queue.root[1]=(uchar*) new_huff_el;
 
1604
    queue_replaced(&queue);
 
1605
  }
 
1606
  huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
 
1607
  huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
 
1608
  return 0;
 
1609
}
 
1610
 
 
1611
static int compare_tree(void* cmp_arg __attribute__((unused)),
 
1612
                        register const uchar *s, register const uchar *t)
 
1613
{
 
1614
  uint length;
 
1615
  for (length=global_count->field_length; length-- ;)
 
1616
    if (*s++ != *t++)
 
1617
      return (int) s[-1] - (int) t[-1];
 
1618
  return 0;
 
1619
}
 
1620
 
 
1621
/*
 
1622
  Organize distinct column values and their incidences into a priority queue.
 
1623
 
 
1624
  SYNOPSIS
 
1625
    save_counts_in_queue()
 
1626
    key                         The column value.
 
1627
    count                       The incidence of this value.
 
1628
    tree                        The Huffman tree to be built later.
 
1629
 
 
1630
  DESCRIPTION
 
1631
    We use the element buffer of the targeted tree. The distinct column
 
1632
    values are organized in a priority queue first. The Huffman
 
1633
    algorithm will later organize the elements into a Huffman tree. For
 
1634
    the time being, we just place references to the elements into the
 
1635
    queue buffer. The buffer will later be organized into a priority
 
1636
    queue.
 
1637
 
 
1638
  RETURN
 
1639
    0
 
1640
 */
 
1641
 
 
1642
static int save_counts_in_queue(uchar *key, element_count count,
 
1643
                                HUFF_TREE *tree)
 
1644
{
 
1645
  HUFF_ELEMENT *new_huff_el;
 
1646
 
 
1647
  new_huff_el=tree->element_buffer+(tree->elements++);
 
1648
  new_huff_el->count=count;
 
1649
  new_huff_el->a.leaf.null=0;
 
1650
  new_huff_el->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
 
1651
    tree->counts->field_length;
 
1652
  queue.root[tree->elements]=(uchar*) new_huff_el;
 
1653
  return 0;
 
1654
}
 
1655
 
 
1656
 
 
1657
/*
 
1658
  Calculate length of file if given counts should be used.
 
1659
 
 
1660
  SYNOPSIS
 
1661
    calc_packed_length()
 
1662
    huff_counts                 The counts for a column of the table(s).
 
1663
    add_tree_lenght             If the decode tree length should be added.
 
1664
 
 
1665
  DESCRIPTION
 
1666
    We need to follow the Huffman algorithm until we know, how many bits
 
1667
    are required for each byte code. But we do not need the resulting
 
1668
    Huffman tree. Hence, we can leave out some steps which are essential
 
1669
    in make_huff_tree().
 
1670
 
 
1671
  RETURN
 
1672
    Number of bytes required to compress this table column.
 
1673
*/
 
1674
 
 
1675
static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
 
1676
                                   uint add_tree_lenght)
 
1677
{
 
1678
  uint i,found,bits_packed,first,last;
 
1679
  my_off_t bytes_packed;
 
1680
  HUFF_ELEMENT element_buffer[256];
 
1681
 
 
1682
  /* 
 
1683
    WARNING: We use a small hack for efficiency: Instead of placing
 
1684
    references to HUFF_ELEMENTs into the queue, we just insert
 
1685
    references to the counts of the byte codes which appeared in this
 
1686
    table column. During the Huffman algorithm they are successively
 
1687
    replaced by references to HUFF_ELEMENTs. This works, because
 
1688
    HUFF_ELEMENTs have the incidence count at their beginning.
 
1689
    Regardless, wether the queue array contains references to counts of
 
1690
    type my_off_t or references to HUFF_ELEMENTs which have the count of
 
1691
    type my_off_t at their beginning, it always points to a count of the
 
1692
    same type.
 
1693
 
 
1694
    Instead of using queue_insert(), we just copy the references into
 
1695
    the buffer of the priority queue. We insert in byte value order, but
 
1696
    the order is in fact irrelevant here. We will establish the correct
 
1697
    order later.
 
1698
  */
 
1699
  first=last=0;
 
1700
  for (i=found=0 ; i < 256 ; i++)
 
1701
  {
 
1702
    if (huff_counts->counts[i])
 
1703
    {
 
1704
      if (! found++)
 
1705
        first=i;
 
1706
      last=i;
 
1707
      /* We start with root[1], which is the queues top element. */
 
1708
      queue.root[found]=(uchar*) &huff_counts->counts[i];
 
1709
    }
 
1710
  }
 
1711
  if (!found)
 
1712
    return(0);                  /* Empty tree */
 
1713
  /*
 
1714
    If there is only a single byte value in this field in all records,
 
1715
    add a second element with zero incidence. This is required to enter
 
1716
    the loop, which follows the Huffman algorithm.
 
1717
  */
 
1718
  if (found < 2)
 
1719
    queue.root[++found]=(uchar*) &huff_counts->counts[last ? 0 : 1];
 
1720
 
 
1721
  /* Make a queue from the queue buffer. */
 
1722
  queue.elements=found;
 
1723
 
 
1724
  bytes_packed=0; bits_packed=0;
 
1725
  /* Add the length of the coding table, which would become part of the file. */
 
1726
  if (add_tree_lenght)
 
1727
    bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
 
1728
                  (max_bit(found-1)+1+1)*(found-2) +7)/8;
 
1729
 
 
1730
  /*
 
1731
    Make a priority queue from the queue. Construct its index so that we
 
1732
    have a partially ordered tree.
 
1733
  */
 
1734
  for (i=(found+1)/2 ; i > 0 ; i--)
 
1735
    _downheap(&queue,i);
 
1736
 
 
1737
  /* The Huffman algorithm. */
 
1738
  for (i=0 ; i < found-1 ; i++)
 
1739
  {
 
1740
    my_off_t        *a;
 
1741
    my_off_t        *b;
 
1742
    HUFF_ELEMENT    *new_huff_el;
 
1743
 
 
1744
    /*
 
1745
      Pop the top element from the queue (the one with the least
 
1746
      incidence). Popping from a priority queue includes a re-ordering
 
1747
      of the queue, to get the next least incidence element to the top.
 
1748
    */
 
1749
    a= (my_off_t*) queue_remove(&queue, 0);
 
1750
    /*
 
1751
      Copy the next least incidence element. The queue implementation
 
1752
      reserves root[0] for temporary purposes. root[1] is the top.
 
1753
    */
 
1754
    b= (my_off_t*) queue.root[1];
 
1755
    /* Create a new element in a local (automatic) buffer. */
 
1756
    new_huff_el= element_buffer + i;
 
1757
    /* The new element gets the sum of the two least incidence elements. */
 
1758
    new_huff_el->count= *a + *b;
 
1759
    /*
 
1760
      The Huffman algorithm assigns another bit to the code for a byte
 
1761
      every time that bytes incidence is combined (directly or indirectly)
 
1762
      to a new element as one of the two least incidence elements.
 
1763
      This means that one more bit per incidence of that byte is required
 
1764
      in the resulting file. So we add the new combined incidence as the
 
1765
      number of bits by which the result grows.
 
1766
    */
 
1767
    bits_packed+=(uint) (new_huff_el->count & 7);
 
1768
    bytes_packed+=new_huff_el->count/8;
 
1769
    /*
 
1770
      Replace the copied top element by the new element and re-order the
 
1771
      queue. This successively replaces the references to counts by
 
1772
      references to HUFF_ELEMENTs.
 
1773
    */
 
1774
    queue.root[1]=(uchar*) new_huff_el;
 
1775
    queue_replaced(&queue);
 
1776
  }
 
1777
  return(bytes_packed+(bits_packed+7)/8);
 
1778
}
 
1779
 
 
1780
 
 
1781
        /* Remove trees that don't give any compression */
 
1782
 
 
1783
static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
 
1784
{
 
1785
  uint k,tree_number;
 
1786
  HUFF_COUNTS count,*i,*j,*last_count;
 
1787
 
 
1788
  last_count=huff_counts+trees;
 
1789
  for (tree_number=0, i=huff_counts ; i < last_count ; i++)
 
1790
  {
 
1791
    if (!i->tree->tree_number)
 
1792
    {
 
1793
      i->tree->tree_number= ++tree_number;
 
1794
      if (i->tree_buff)
 
1795
        continue;                       /* Don't join intervall */
 
1796
      for (j=i+1 ; j < last_count ; j++)
 
1797
      {
 
1798
        if (! j->tree->tree_number && ! j->tree_buff)
 
1799
        {
 
1800
          for (k=0 ; k < 256 ; k++)
 
1801
            count.counts[k]=i->counts[k]+j->counts[k];
 
1802
          if (calc_packed_length(&count,1) <=
 
1803
              i->tree->bytes_packed + j->tree->bytes_packed+
 
1804
              i->tree->tree_pack_length+j->tree->tree_pack_length+
 
1805
              ALLOWED_JOIN_DIFF)
 
1806
          {
 
1807
            memcpy_fixed((uchar*) i->counts,(uchar*) count.counts,
 
1808
                         sizeof(count.counts[0])*256);
 
1809
            my_free((uchar*) j->tree->element_buffer,MYF(0));
 
1810
            j->tree->element_buffer=0;
 
1811
            j->tree=i->tree;
 
1812
            bmove((uchar*) i->counts,(uchar*) count.counts,
 
1813
                  sizeof(count.counts[0])*256);
 
1814
            if (make_huff_tree(i->tree,i))
 
1815
              return (uint) -1;
 
1816
          }
 
1817
        }
 
1818
      }
 
1819
    }
 
1820
  }
 
1821
  if (verbose)
 
1822
    VOID(printf("Original trees:  %d  After join: %d\n", trees, tree_number));
 
1823
  return tree_number;                   /* Return trees left */
 
1824
}
 
1825
 
 
1826
 
 
1827
/*
 
1828
  Fill in huff_tree encode tables.
 
1829
 
 
1830
  SYNOPSIS
 
1831
    make_huff_decode_table()
 
1832
    huff_tree               An array of HUFF_TREE which are to be encoded.
 
1833
    trees                   The number of HUFF_TREE in the array.
 
1834
 
 
1835
  RETURN
 
1836
    0           success
 
1837
    != 0        error
 
1838
*/
 
1839
 
 
1840
static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
 
1841
{
 
1842
  uint elements;
 
1843
  for ( ; trees-- ; huff_tree++)
 
1844
  {
 
1845
    if (huff_tree->tree_number > 0)
 
1846
    {
 
1847
      elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
 
1848
      if (!(huff_tree->code =
 
1849
            (uint64_t*) my_malloc(elements*
 
1850
                                   (sizeof(uint64_t) + sizeof(uchar)),
 
1851
                                   MYF(MY_WME | MY_ZEROFILL))))
 
1852
        return 1;
 
1853
      huff_tree->code_len=(uchar*) (huff_tree->code+elements);
 
1854
      make_traverse_code_tree(huff_tree, huff_tree->root,
 
1855
                              8 * sizeof(uint64_t), 0LL);
 
1856
    }
 
1857
  }
 
1858
  return 0;
 
1859
}
 
1860
 
 
1861
 
 
1862
static void make_traverse_code_tree(HUFF_TREE *huff_tree,
 
1863
                                    HUFF_ELEMENT *element,
 
1864
                                    uint size, uint64_t code)
 
1865
{
 
1866
  uint chr;
 
1867
  if (!element->a.leaf.null)
 
1868
  {
 
1869
    chr=element->a.leaf.element_nr;
 
1870
    huff_tree->code_len[chr]= (uchar) (8 * sizeof(uint64_t) - size);
 
1871
    huff_tree->code[chr]= (code >> size);
 
1872
    if (huff_tree->height < 8 * sizeof(uint64_t) - size)
 
1873
        huff_tree->height= 8 * sizeof(uint64_t) - size;
 
1874
  }
 
1875
  else
 
1876
  {
 
1877
    size--;
 
1878
    make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
 
1879
    make_traverse_code_tree(huff_tree, element->a.nod.right, size,
 
1880
                            code + (((uint64_t) 1) << size));
 
1881
  }
 
1882
  return;
 
1883
}
 
1884
 
 
1885
 
 
1886
/*
 
1887
  Convert a value into binary digits.
 
1888
 
 
1889
  SYNOPSIS
 
1890
    bindigits()
 
1891
    value                       The value.
 
1892
    length                      The number of low order bits to convert.
 
1893
 
 
1894
  NOTE
 
1895
    The result string is in static storage. It is reused on every call.
 
1896
    So you cannot use it twice in one expression.
 
1897
 
 
1898
  RETURN
 
1899
    A pointer to a static NUL-terminated string.
 
1900
 */
 
1901
 
 
1902
static char *bindigits(uint64_t value, uint bits)
 
1903
{
 
1904
  static char digits[72];
 
1905
  char *ptr= digits;
 
1906
  uint idx= bits;
 
1907
 
 
1908
  assert(idx < sizeof(digits));
 
1909
  while (idx)
 
1910
    *(ptr++)= '0' + ((char) (value >> (--idx)) & (char) 1);
 
1911
  *ptr= '\0';
 
1912
  return digits;
 
1913
}
 
1914
 
 
1915
 
 
1916
/*
 
1917
  Convert a value into hexadecimal digits.
 
1918
 
 
1919
  SYNOPSIS
 
1920
    hexdigits()
 
1921
    value                       The value.
 
1922
 
 
1923
  NOTE
 
1924
    The result string is in static storage. It is reused on every call.
 
1925
    So you cannot use it twice in one expression.
 
1926
 
 
1927
  RETURN
 
1928
    A pointer to a static NUL-terminated string.
 
1929
 */
 
1930
 
 
1931
static char *hexdigits(uint64_t value)
 
1932
{
 
1933
  static char digits[20];
 
1934
  char *ptr= digits;
 
1935
  uint idx= 2 * sizeof(value); /* Two hex digits per byte. */
 
1936
 
 
1937
  assert(idx < sizeof(digits));
 
1938
  while (idx)
 
1939
  {
 
1940
    if ((*(ptr++)= '0' + ((char) (value >> (4 * (--idx))) & (char) 0xf)) > '9')
 
1941
      *(ptr - 1)+= 'a' - '9' - 1;
 
1942
  }
 
1943
  *ptr= '\0';
 
1944
  return digits;
 
1945
}
 
1946
 
 
1947
 
 
1948
        /* Write header to new packed data file */
 
1949
 
 
1950
static int write_header(PACK_MRG_INFO *mrg,uint head_length,uint trees,
 
1951
                        my_off_t tot_elements,my_off_t filelength)
 
1952
{
 
1953
  uchar *buff= (uchar*) file_buffer.pos;
 
1954
 
 
1955
  bzero(buff,HEAD_LENGTH);
 
1956
  memcpy_fixed(buff,myisam_pack_file_magic,4);
 
1957
  int4store(buff+4,head_length);
 
1958
  int4store(buff+8, mrg->min_pack_length);
 
1959
  int4store(buff+12,mrg->max_pack_length);
 
1960
  int4store(buff+16,tot_elements);
 
1961
  int4store(buff+20,intervall_length);
 
1962
  int2store(buff+24,trees);
 
1963
  buff[26]=(char) mrg->ref_length;
 
1964
        /* Save record pointer length */
 
1965
  buff[27]= (uchar) mi_get_pointer_length((uint64_t) filelength,2);
 
1966
  if (test_only)
 
1967
    return 0;
 
1968
  VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
 
1969
  return my_write(file_buffer.file,(const uchar *) file_buffer.pos,HEAD_LENGTH,
 
1970
                  MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
 
1971
}
 
1972
 
 
1973
        /* Write fieldinfo to new packed file */
 
1974
 
 
1975
static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
 
1976
{
 
1977
  register uint i;
 
1978
  uint huff_tree_bits;
 
1979
  huff_tree_bits=max_bit(trees ? trees-1 : 0);
 
1980
 
 
1981
  if (verbose >= 2)
 
1982
  {
 
1983
    VOID(printf("\n"));
 
1984
    VOID(printf("column types:\n"));
 
1985
    VOID(printf("FIELD_NORMAL          0\n"));
 
1986
    VOID(printf("FIELD_SKIP_ENDSPACE   1\n"));
 
1987
    VOID(printf("FIELD_SKIP_PRESPACE   2\n"));
 
1988
    VOID(printf("FIELD_SKIP_ZERO       3\n"));
 
1989
    VOID(printf("FIELD_BLOB            4\n"));
 
1990
    VOID(printf("FIELD_CONSTANT        5\n"));
 
1991
    VOID(printf("FIELD_INTERVALL       6\n"));
 
1992
    VOID(printf("FIELD_ZERO            7\n"));
 
1993
    VOID(printf("FIELD_VARCHAR         8\n"));
 
1994
    VOID(printf("FIELD_CHECK           9\n"));
 
1995
    VOID(printf("\n"));
 
1996
    VOID(printf("pack type as a set of flags:\n"));
 
1997
    VOID(printf("PACK_TYPE_SELECTED      1\n"));
 
1998
    VOID(printf("PACK_TYPE_SPACE_FIELDS  2\n"));
 
1999
    VOID(printf("PACK_TYPE_ZERO_FILL     4\n"));
 
2000
    VOID(printf("\n"));
 
2001
  }
 
2002
  for (i=0 ; i++ < fields ; counts++)
 
2003
  {
 
2004
    write_bits((uint64_t) (int) counts->field_type, 5);
 
2005
    write_bits(counts->pack_type,6);
 
2006
    if (counts->pack_type & PACK_TYPE_ZERO_FILL)
 
2007
      write_bits(counts->max_zero_fill,5);
 
2008
    else
 
2009
      write_bits(counts->length_bits,5);
 
2010
    write_bits((uint64_t) counts->tree->tree_number - 1, huff_tree_bits);
 
2011
    if (verbose >= 2)
 
2012
      VOID(printf("column: %3u  type: %2u  pack: %2u  zero: %4u  lbits: %2u  "
 
2013
                  "tree: %2u  length: %4u\n", i , counts->field_type,
 
2014
                  counts->pack_type, counts->max_zero_fill, counts->length_bits,
 
2015
                  counts->tree->tree_number, counts->field_length));
 
2016
  }
 
2017
  flush_bits();
 
2018
  return;
 
2019
}
 
2020
 
 
2021
        /* Write all huff_trees to new datafile. Return tot count of
 
2022
           elements in all trees
 
2023
           Returns 0 on error */
 
2024
 
 
2025
static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
 
2026
{
 
2027
  uint i,int_length;
 
2028
  uint tree_no;
 
2029
  uint codes;
 
2030
  uint errors= 0;
 
2031
  uint *packed_tree,*offset,length;
 
2032
  my_off_t elements;
 
2033
 
 
2034
  /* Find the highest number of elements in the trees. */
 
2035
  for (i=length=0 ; i < trees ; i++)
 
2036
    if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
 
2037
      length=huff_tree[i].elements;
 
2038
  /*
 
2039
    Allocate a buffer for packing a decode tree. Two numbers per element
 
2040
    (left child and right child).
 
2041
  */
 
2042
  if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
 
2043
  {
 
2044
    my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
 
2045
    return 0;
 
2046
  }
 
2047
 
 
2048
  if (verbose >= 2)
 
2049
    VOID(printf("\n"));
 
2050
  tree_no= 0;
 
2051
  intervall_length=0;
 
2052
  for (elements=0; trees-- ; huff_tree++)
 
2053
  {
 
2054
    /* Skip columns that have been joined with other columns. */
 
2055
    if (huff_tree->tree_number == 0)
 
2056
      continue;                         /* Deleted tree */
 
2057
    tree_no++;
 
2058
    if (verbose >= 3)
 
2059
      VOID(printf("\n"));
 
2060
    /* Count the total number of elements (byte codes or column values). */
 
2061
    elements+=huff_tree->elements;
 
2062
    huff_tree->max_offset=2;
 
2063
    /* Build a tree of offsets and codes for decoding in 'packed_tree'. */
 
2064
    if (huff_tree->elements <= 1)
 
2065
      offset=packed_tree;
 
2066
    else
 
2067
      offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
 
2068
 
 
2069
    /* This should be the same as 'length' above. */
 
2070
    huff_tree->offset_bits=max_bit(huff_tree->max_offset);
 
2071
 
 
2072
    /*
 
2073
      Since we check this during collecting the distinct column values,
 
2074
      this should never happen.
 
2075
    */
 
2076
    if (huff_tree->max_offset >= IS_OFFSET)
 
2077
    {                           /* This should be impossible */
 
2078
      VOID(fprintf(stderr, "Tree offset got too big: %d, aborted\n",
 
2079
                   huff_tree->max_offset));
 
2080
      my_afree((uchar*) packed_tree);
 
2081
      return 0;
 
2082
    }
 
2083
 
 
2084
    if (!huff_tree->counts->tree_buff)
 
2085
    {
 
2086
      /* We do a byte compression on this column. Mark with bit 0. */
 
2087
      write_bits(0,1);
 
2088
      write_bits(huff_tree->min_chr,8);
 
2089
      write_bits(huff_tree->elements,9);
 
2090
      write_bits(huff_tree->char_bits,5);
 
2091
      write_bits(huff_tree->offset_bits,5);
 
2092
      int_length=0;
 
2093
    }
 
2094
    else
 
2095
    {
 
2096
      int_length=(uint) (huff_tree->counts->tree_pos -
 
2097
                         huff_tree->counts->tree_buff);
 
2098
      /* We have distinct column values for this column. Mark with bit 1. */
 
2099
      write_bits(1,1);
 
2100
      write_bits(huff_tree->elements,15);
 
2101
      write_bits(int_length,16);
 
2102
      write_bits(huff_tree->char_bits,5);
 
2103
      write_bits(huff_tree->offset_bits,5);
 
2104
      intervall_length+=int_length;
 
2105
    }
 
2106
    if (verbose >= 2)
 
2107
      VOID(printf("tree: %2u  elements: %4u  char_bits: %2u  offset_bits: %2u  "
 
2108
                  "%s: %5u  codelen: %2u\n", tree_no, huff_tree->elements,
 
2109
                  huff_tree->char_bits, huff_tree->offset_bits,
 
2110
                  huff_tree->counts->tree_buff ? "bufflen" : "min_chr",
 
2111
                  huff_tree->counts->tree_buff ? int_length :
 
2112
                  huff_tree->min_chr, huff_tree->height));
 
2113
 
 
2114
    /* Check that the code tree length matches the element count. */
 
2115
    length=(uint) (offset-packed_tree);
 
2116
    if (length != huff_tree->elements*2-2)
 
2117
    {
 
2118
      VOID(fprintf(stderr, "error: Huff-tree-length: %d != calc_length: %d\n",
 
2119
                   length, huff_tree->elements * 2 - 2));
 
2120
      errors++;
 
2121
      break;
 
2122
    }
 
2123
 
 
2124
    for (i=0 ; i < length ; i++)
 
2125
    {
 
2126
      if (packed_tree[i] & IS_OFFSET)
 
2127
        write_bits(packed_tree[i] - IS_OFFSET+ (1 << huff_tree->offset_bits),
 
2128
                   huff_tree->offset_bits+1);
 
2129
      else
 
2130
        write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
 
2131
      if (verbose >= 3)
 
2132
        VOID(printf("tree[0x%04x]: %s0x%04x\n",
 
2133
                    i, (packed_tree[i] & IS_OFFSET) ? " -> " : "",
 
2134
                    (packed_tree[i] & IS_OFFSET) ?
 
2135
                    packed_tree[i] - IS_OFFSET + i : packed_tree[i]));
 
2136
    }
 
2137
    flush_bits();
 
2138
 
 
2139
    /*
 
2140
      Display coding tables and check their correctness.
 
2141
    */
 
2142
    codes= huff_tree->counts->tree_buff ? huff_tree->elements : 256;
 
2143
    for (i= 0; i < codes; i++)
 
2144
    {
 
2145
      uint64_t code;
 
2146
      uint bits;
 
2147
      uint len;
 
2148
      uint idx;
 
2149
 
 
2150
      if (! (len= huff_tree->code_len[i]))
 
2151
        continue;
 
2152
      if (verbose >= 3)
 
2153
        VOID(printf("code[0x%04x]:      0x%s  bits: %2u  bin: %s\n", i,
 
2154
                    hexdigits(huff_tree->code[i]), huff_tree->code_len[i],
 
2155
                    bindigits(huff_tree->code[i], huff_tree->code_len[i])));
 
2156
 
 
2157
      /* Check that the encode table decodes correctly. */
 
2158
      code= 0;
 
2159
      bits= 0;
 
2160
      idx= 0;
 
2161
      for (;;)
 
2162
      {
 
2163
        if (! len)
 
2164
        {
 
2165
          VOID(fflush(stdout));
 
2166
          VOID(fprintf(stderr, "error: code 0x%s with %u bits not found\n",
 
2167
                       hexdigits(huff_tree->code[i]), huff_tree->code_len[i]));
 
2168
          errors++;
 
2169
          break;
 
2170
        }
 
2171
        code<<= 1;
 
2172
        code|= (huff_tree->code[i] >> (--len)) & 1;
 
2173
        bits++;
 
2174
        if (bits > 8 * sizeof(code))
 
2175
        {
 
2176
          VOID(fflush(stdout));
 
2177
          VOID(fprintf(stderr, "error: Huffman code too long: %u/%u\n",
 
2178
                       bits, (uint) (8 * sizeof(code))));
 
2179
          errors++;
 
2180
          break;
 
2181
        }
 
2182
        idx+= (uint) code & 1;
 
2183
        if (idx >= length)
 
2184
        {
 
2185
          VOID(fflush(stdout));
 
2186
          VOID(fprintf(stderr, "error: illegal tree offset: %u/%u\n",
 
2187
                       idx, length));
 
2188
          errors++;
 
2189
          break;
 
2190
        }
 
2191
        if (packed_tree[idx] & IS_OFFSET)
 
2192
          idx+= packed_tree[idx] & ~IS_OFFSET;
 
2193
        else
 
2194
          break; /* Hit a leaf. This contains the result value. */
 
2195
      }
 
2196
      if (errors)
 
2197
        break;
 
2198
 
 
2199
      if (packed_tree[idx] != i)
 
2200
      {
 
2201
        VOID(fflush(stdout));
 
2202
        VOID(fprintf(stderr, "error: decoded value 0x%04x  should be: 0x%04x\n",
 
2203
                     packed_tree[idx], i));
 
2204
        errors++;
 
2205
        break;
 
2206
      }
 
2207
    } /*end for (codes)*/
 
2208
    if (errors)
 
2209
      break;
 
2210
 
 
2211
    /* Write column values in case of distinct column value compression. */
 
2212
    if (huff_tree->counts->tree_buff)
 
2213
    {
 
2214
      for (i=0 ; i < int_length ; i++)
 
2215
      {
 
2216
        write_bits((uint64_t) (uchar) huff_tree->counts->tree_buff[i], 8);
 
2217
        if (verbose >= 3)
 
2218
          VOID(printf("column_values[0x%04x]: 0x%02x\n",
 
2219
                      i, (uchar) huff_tree->counts->tree_buff[i]));
 
2220
      }
 
2221
    }
 
2222
    flush_bits();
 
2223
  }
 
2224
  if (verbose >= 2)
 
2225
    VOID(printf("\n"));
 
2226
  my_afree((uchar*) packed_tree);
 
2227
  if (errors)
 
2228
  {
 
2229
    VOID(fprintf(stderr, "Error: Generated decode trees are corrupt. Stop.\n"));
 
2230
    return 0;
 
2231
  }
 
2232
  return elements;
 
2233
}
 
2234
 
 
2235
 
 
2236
static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
 
2237
                                   uint *offset)
 
2238
{
 
2239
  uint *prev_offset;
 
2240
 
 
2241
  prev_offset= offset;
 
2242
  /*
 
2243
    'a.leaf.null' takes the same place as 'a.nod.left'. If this is null,
 
2244
    then there is no left child and, hence no right child either. This
 
2245
    is a property of a binary tree. An element is either a node with two
 
2246
    childs, or a leaf without childs.
 
2247
 
 
2248
    The current element is always a node with two childs. Go left first.
 
2249
  */
 
2250
  if (!element->a.nod.left->a.leaf.null)
 
2251
  {
 
2252
    /* Store the byte code or the index of the column value. */
 
2253
    prev_offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
 
2254
    offset+=2;
 
2255
  }
 
2256
  else
 
2257
  {
 
2258
    /*
 
2259
      Recursively traverse the tree to the left. Mark it as an offset to
 
2260
      another tree node (in contrast to a byte code or column value index).
 
2261
    */
 
2262
    prev_offset[0]= IS_OFFSET+2;
 
2263
    offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
 
2264
  }
 
2265
 
 
2266
  /* Now, check the right child. */
 
2267
  if (!element->a.nod.right->a.leaf.null)
 
2268
  {
 
2269
    /* Store the byte code or the index of the column value. */
 
2270
    prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
 
2271
    return offset;
 
2272
  }
 
2273
  else
 
2274
  {
 
2275
    /*
 
2276
      Recursively traverse the tree to the right. Mark it as an offset to
 
2277
      another tree node (in contrast to a byte code or column value index).
 
2278
    */
 
2279
    uint temp=(uint) (offset-prev_offset-1);
 
2280
    prev_offset[1]= IS_OFFSET+ temp;
 
2281
    if (huff_tree->max_offset < temp)
 
2282
      huff_tree->max_offset = temp;
 
2283
    return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
 
2284
  }
 
2285
}
 
2286
 
 
2287
        /* Get number of bits neaded to represent value */
 
2288
 
 
2289
static uint max_bit(register uint value)
 
2290
{
 
2291
  register uint power=1;
 
2292
 
 
2293
  while ((value>>=1))
 
2294
    power++;
 
2295
  return (power);
 
2296
}
 
2297
 
 
2298
 
 
2299
static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
 
2300
{
 
2301
  int error;
 
2302
  uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
 
2303
    intervall,field_length,max_pack_length,pack_blob_length;
 
2304
  my_off_t record_count;
 
2305
  char llbuf[32];
 
2306
  ulong length,pack_length;
 
2307
  uchar *record,*pos,*end_pos,*record_pos,*start_pos;
 
2308
  HUFF_COUNTS *count,*end_count;
 
2309
  HUFF_TREE *tree;
 
2310
  MI_INFO *isam_file=mrg->file[0];
 
2311
  uint pack_version= (uint) isam_file->s->pack.version;
 
2312
 
 
2313
  /* Allocate a buffer for the records (excluding blobs). */
 
2314
  if (!(record=(uchar*) my_alloca(isam_file->s->base.reclength)))
 
2315
    return -1;
 
2316
 
 
2317
  end_count=huff_counts+isam_file->s->base.fields;
 
2318
  min_record_length= (uint) ~0;
 
2319
  max_record_length=0;
 
2320
 
 
2321
  /*
 
2322
    Calculate the maximum number of bits required to pack the records.
 
2323
    Remember to understand 'max_zero_fill' as 'min_zero_fill'.
 
2324
    The tree height determines the maximum number of bits per value.
 
2325
    Some fields skip leading or trailing spaces or zeroes. The skipped
 
2326
    number of bytes is encoded by 'length_bits' bits.
 
2327
    Empty blobs and varchar are encoded with a single 1 bit. Other blobs
 
2328
    and varchar get a leading 0 bit.
 
2329
  */
 
2330
  for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
 
2331
  {
 
2332
    if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
 
2333
      huff_counts[i].max_zero_fill=0;
 
2334
    if (huff_counts[i].field_type == FIELD_CONSTANT ||
 
2335
        huff_counts[i].field_type == FIELD_ZERO ||
 
2336
        huff_counts[i].field_type == FIELD_CHECK)
 
2337
      continue;
 
2338
    if (huff_counts[i].field_type == FIELD_INTERVALL)
 
2339
      max_calc_length+=huff_counts[i].tree->height;
 
2340
    else if (huff_counts[i].field_type == FIELD_BLOB ||
 
2341
             huff_counts[i].field_type == FIELD_VARCHAR)
 
2342
      max_calc_length+=huff_counts[i].tree->height*huff_counts[i].max_length + huff_counts[i].length_bits +1;
 
2343
    else
 
2344
      max_calc_length+=
 
2345
        (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
 
2346
          huff_counts[i].tree->height+huff_counts[i].length_bits;
 
2347
  }
 
2348
  max_calc_length= (max_calc_length + 7) / 8;
 
2349
  pack_ref_length= calc_pack_length(pack_version, max_calc_length);
 
2350
  record_count=0;
 
2351
  /* 'max_blob_length' is the max length of all blobs of a record. */
 
2352
  pack_blob_length= isam_file->s->base.blobs ?
 
2353
                    calc_pack_length(pack_version, mrg->max_blob_length) : 0;
 
2354
  max_pack_length=pack_ref_length+pack_blob_length;
 
2355
 
 
2356
  mrg_reset(mrg);
 
2357
  while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
 
2358
  {
 
2359
    ulong tot_blob_length=0;
 
2360
    if (! error)
 
2361
    {
 
2362
      if (flush_buffer((ulong) max_calc_length + (ulong) max_pack_length))
 
2363
        break;
 
2364
      record_pos= (uchar*) file_buffer.pos;
 
2365
      file_buffer.pos+=max_pack_length;
 
2366
      for (start_pos=record, count= huff_counts; count < end_count ; count++)
 
2367
      {
 
2368
        end_pos=start_pos+(field_length=count->field_length);
 
2369
        tree=count->tree;
 
2370
 
 
2371
        /* Check if the column contains spaces only. */
 
2372
        if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
 
2373
        {
 
2374
          for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
 
2375
          if (pos == end_pos)
 
2376
          {
 
2377
            write_bits(1,1);
 
2378
            start_pos=end_pos;
 
2379
            continue;
 
2380
          }
 
2381
          write_bits(0,1);
 
2382
        }
 
2383
        end_pos-=count->max_zero_fill;
 
2384
        field_length-=count->max_zero_fill;
 
2385
 
 
2386
        switch (count->field_type) {
 
2387
        case FIELD_SKIP_ZERO:
 
2388
          if (!memcmp((uchar*) start_pos,zero_string,field_length))
 
2389
          {
 
2390
            write_bits(1,1);
 
2391
            start_pos=end_pos;
 
2392
            break;
 
2393
          }
 
2394
          write_bits(0,1);
 
2395
          /* Fall through */
 
2396
        case FIELD_NORMAL:
 
2397
          for ( ; start_pos < end_pos ; start_pos++)
 
2398
          {
 
2399
            write_bits(tree->code[(uchar) *start_pos],
 
2400
                       (uint) tree->code_len[(uchar) *start_pos]);
 
2401
          }
 
2402
          break;
 
2403
        case FIELD_SKIP_ENDSPACE:
 
2404
          for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
 
2405
          length= (ulong) (end_pos - pos);
 
2406
          if (count->pack_type & PACK_TYPE_SELECTED)
 
2407
          {
 
2408
            if (length > count->min_space)
 
2409
            {
 
2410
              write_bits(1,1);
 
2411
              write_bits(length,count->length_bits);
 
2412
            }
 
2413
            else
 
2414
            {
 
2415
              write_bits(0,1);
 
2416
              pos=end_pos;
 
2417
            }
 
2418
          }
 
2419
          else
 
2420
          {
 
2421
            write_bits(length,count->length_bits);
 
2422
          }
 
2423
          /* Encode all significant bytes. */
 
2424
          for ( ; start_pos < pos ; start_pos++)
 
2425
          {
 
2426
            write_bits(tree->code[(uchar) *start_pos],
 
2427
                       (uint) tree->code_len[(uchar) *start_pos]);
 
2428
          }
 
2429
          start_pos=end_pos;
 
2430
          break;
 
2431
        case FIELD_SKIP_PRESPACE:
 
2432
          for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
 
2433
          length= (ulong) (pos - start_pos);
 
2434
          if (count->pack_type & PACK_TYPE_SELECTED)
 
2435
          {
 
2436
            if (length > count->min_space)
 
2437
            {
 
2438
              write_bits(1,1);
 
2439
              write_bits(length,count->length_bits);
 
2440
            }
 
2441
            else
 
2442
            {
 
2443
              pos=start_pos;
 
2444
              write_bits(0,1);
 
2445
            }
 
2446
          }
 
2447
          else
 
2448
          {
 
2449
            write_bits(length,count->length_bits);
 
2450
          }
 
2451
          /* Encode all significant bytes. */
 
2452
          for (start_pos=pos ; start_pos < end_pos ; start_pos++)
 
2453
          {
 
2454
            write_bits(tree->code[(uchar) *start_pos],
 
2455
                       (uint) tree->code_len[(uchar) *start_pos]);
 
2456
          }
 
2457
          break;
 
2458
        case FIELD_CONSTANT:
 
2459
        case FIELD_ZERO:
 
2460
        case FIELD_CHECK:
 
2461
          start_pos=end_pos;
 
2462
          break;
 
2463
        case FIELD_INTERVALL:
 
2464
          global_count=count;
 
2465
          pos=(uchar*) tree_search(&count->int_tree, start_pos,
 
2466
                                  count->int_tree.custom_arg);
 
2467
          intervall=(uint) (pos - count->tree_buff)/field_length;
 
2468
          write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
 
2469
          start_pos=end_pos;
 
2470
          break;
 
2471
        case FIELD_BLOB:
 
2472
        {
 
2473
          ulong blob_length=_mi_calc_blob_length(field_length-
 
2474
                                                 portable_sizeof_char_ptr,
 
2475
                                                 start_pos);
 
2476
          /* Empty blobs are encoded with a single 1 bit. */
 
2477
          if (!blob_length)
 
2478
          {
 
2479
            write_bits(1,1);
 
2480
          }
 
2481
          else
 
2482
          {
 
2483
            uchar *blob,*blob_end;
 
2484
            write_bits(0,1);
 
2485
            /* Write the blob length. */
 
2486
            write_bits(blob_length,count->length_bits);
 
2487
            memcpy_fixed(&blob,end_pos-portable_sizeof_char_ptr,
 
2488
                         sizeof(char*));
 
2489
            blob_end=blob+blob_length;
 
2490
            /* Encode the blob bytes. */
 
2491
            for ( ; blob < blob_end ; blob++)
 
2492
            {
 
2493
              write_bits(tree->code[(uchar) *blob],
 
2494
                         (uint) tree->code_len[(uchar) *blob]);
 
2495
            }
 
2496
            tot_blob_length+=blob_length;
 
2497
          }
 
2498
          start_pos= end_pos;
 
2499
          break;
 
2500
        }
 
2501
        case FIELD_VARCHAR:
 
2502
        {
 
2503
          uint var_pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
 
2504
          ulong col_length= (var_pack_length == 1 ?
 
2505
                             (uint) *(uchar*) start_pos :
 
2506
                             uint2korr(start_pos));
 
2507
          /* Empty varchar are encoded with a single 1 bit. */
 
2508
          if (!col_length)
 
2509
          {
 
2510
            write_bits(1,1);                    /* Empty varchar */
 
2511
          }
 
2512
          else
 
2513
          {
 
2514
            uchar *end= start_pos + var_pack_length + col_length;
 
2515
            write_bits(0,1);
 
2516
            /* Write the varchar length. */
 
2517
            write_bits(col_length,count->length_bits);
 
2518
            /* Encode the varchar bytes. */
 
2519
            for (start_pos+= var_pack_length ; start_pos < end ; start_pos++)
 
2520
            {
 
2521
              write_bits(tree->code[(uchar) *start_pos],
 
2522
                         (uint) tree->code_len[(uchar) *start_pos]);
 
2523
            }
 
2524
          }
 
2525
          start_pos= end_pos;
 
2526
          break;
 
2527
        }
 
2528
        case FIELD_LAST:
 
2529
        case FIELD_enum_val_count:
 
2530
          abort();                              /* Impossible */
 
2531
        }
 
2532
        start_pos+=count->max_zero_fill;
 
2533
      }
 
2534
      flush_bits();
 
2535
      length=(ulong) ((uchar*) file_buffer.pos - record_pos) - max_pack_length;
 
2536
      pack_length= save_pack_length(pack_version, record_pos, length);
 
2537
      if (pack_blob_length)
 
2538
        pack_length+= save_pack_length(pack_version, record_pos + pack_length,
 
2539
                                       tot_blob_length);
 
2540
      /* Correct file buffer if the header was smaller */
 
2541
      if (pack_length != max_pack_length)
 
2542
      {
 
2543
        bmove(record_pos+pack_length,record_pos+max_pack_length,length);
 
2544
        file_buffer.pos-= (max_pack_length-pack_length);
 
2545
      }
 
2546
      if (length < (ulong) min_record_length)
 
2547
        min_record_length=(uint) length;
 
2548
      if (length > (ulong) max_record_length)
 
2549
        max_record_length=(uint) length;
 
2550
      record_count++;
 
2551
      if (write_loop && record_count % WRITE_COUNT == 0)
 
2552
      {
 
2553
        VOID(printf("%lu\r", (ulong) record_count));
 
2554
        VOID(fflush(stdout));
 
2555
      }
 
2556
    }
 
2557
    else if (error != HA_ERR_RECORD_DELETED)
 
2558
      break;
 
2559
  }
 
2560
  if (error == HA_ERR_END_OF_FILE)
 
2561
    error=0;
 
2562
  else
 
2563
  {
 
2564
    VOID(fprintf(stderr, "%s: Got error %d reading records\n",
 
2565
                 my_progname, error));
 
2566
  }
 
2567
  if (verbose >= 2)
 
2568
    VOID(printf("wrote %s records.\n", llstr((int64_t) record_count, llbuf)));
 
2569
 
 
2570
  my_afree((uchar*) record);
 
2571
  mrg->ref_length=max_pack_length;
 
2572
  mrg->min_pack_length=max_record_length ? min_record_length : 0;
 
2573
  mrg->max_pack_length=max_record_length;
 
2574
  return(error || error_on_write || flush_buffer(~(ulong) 0));
 
2575
}
 
2576
 
 
2577
 
 
2578
static char *make_new_name(char *new_name, char *old_name)
 
2579
{
 
2580
  return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
 
2581
}
 
2582
 
 
2583
static char *make_old_name(char *new_name, char *old_name)
 
2584
{
 
2585
  return fn_format(new_name,old_name,"",OLD_EXT,2+4);
 
2586
}
 
2587
 
 
2588
        /* rutines for bit writing buffer */
 
2589
 
 
2590
static void init_file_buffer(File file, bool read_buffer)
 
2591
{
 
2592
  file_buffer.file=file;
 
2593
  file_buffer.buffer= (uchar*) my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),
 
2594
                                         MYF(MY_WME));
 
2595
  file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-8;
 
2596
  file_buffer.pos_in_file=0;
 
2597
  error_on_write=0;
 
2598
  if (read_buffer)
 
2599
  {
 
2600
 
 
2601
    file_buffer.pos=file_buffer.end;
 
2602
    file_buffer.bits=0;
 
2603
  }
 
2604
  else
 
2605
  {
 
2606
    file_buffer.pos=file_buffer.buffer;
 
2607
    file_buffer.bits=BITS_SAVED;
 
2608
  }
 
2609
  file_buffer.bitbucket= 0;
 
2610
}
 
2611
 
 
2612
 
 
2613
static int flush_buffer(ulong neaded_length)
 
2614
{
 
2615
  ulong length;
 
2616
 
 
2617
  /*
 
2618
    file_buffer.end is 8 bytes lower than the real end of the buffer.
 
2619
    This is done so that the end-of-buffer condition does not need to be
 
2620
    checked for every byte (see write_bits()). Consequently,
 
2621
    file_buffer.pos can become greater than file_buffer.end. The
 
2622
    algorithms in the other functions ensure that there will never be
 
2623
    more than 8 bytes written to the buffer without an end-of-buffer
 
2624
    check. So the buffer cannot be overrun. But we need to check for the
 
2625
    near-to-buffer-end condition to avoid a negative result, which is
 
2626
    casted to unsigned and thus becomes giant.
 
2627
  */
 
2628
  if ((file_buffer.pos < file_buffer.end) &&
 
2629
      ((ulong) (file_buffer.end - file_buffer.pos) > neaded_length))
 
2630
    return 0;
 
2631
  length=(ulong) (file_buffer.pos-file_buffer.buffer);
 
2632
  file_buffer.pos=file_buffer.buffer;
 
2633
  file_buffer.pos_in_file+=length;
 
2634
  if (test_only)
 
2635
    return 0;
 
2636
  if (error_on_write|| my_write(file_buffer.file,
 
2637
                                (const uchar*) file_buffer.buffer,
 
2638
                                length,
 
2639
                                MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
 
2640
  {
 
2641
    error_on_write=1;
 
2642
    return 1;
 
2643
  }
 
2644
 
 
2645
  if (neaded_length != ~(ulong) 0 &&
 
2646
      (ulong) (file_buffer.end-file_buffer.buffer) < neaded_length)
 
2647
  {
 
2648
    char *tmp;
 
2649
    neaded_length+=256;                         /* some margin */
 
2650
    tmp= my_realloc((char*) file_buffer.buffer, neaded_length,MYF(MY_WME));
 
2651
    if (!tmp)
 
2652
      return 1;
 
2653
    file_buffer.pos= ((uchar*) tmp +
 
2654
                      (ulong) (file_buffer.pos - file_buffer.buffer));
 
2655
    file_buffer.buffer= (uchar*) tmp;
 
2656
    file_buffer.end= (uchar*) (tmp+neaded_length-8);
 
2657
  }
 
2658
  return 0;
 
2659
}
 
2660
 
 
2661
 
 
2662
static void end_file_buffer(void)
 
2663
{
 
2664
  my_free((uchar*) file_buffer.buffer,MYF(0));
 
2665
}
 
2666
 
 
2667
        /* output `bits` low bits of `value' */
 
2668
 
 
2669
static void write_bits(register uint64_t value, register uint bits)
 
2670
{
 
2671
  assert(((bits < 8 * sizeof(value)) && ! (value >> bits)) ||
 
2672
              (bits == 8 * sizeof(value)));
 
2673
 
 
2674
  if ((file_buffer.bits-= (int) bits) >= 0)
 
2675
  {
 
2676
    file_buffer.bitbucket|= value << file_buffer.bits;
 
2677
  }
 
2678
  else
 
2679
  {
 
2680
    register uint64_t bit_buffer;
 
2681
    bits= (uint) -file_buffer.bits;
 
2682
    bit_buffer= (file_buffer.bitbucket |
 
2683
                 ((bits != 8 * sizeof(value)) ? (value >> bits) : 0));
 
2684
#if BITS_SAVED == 64
 
2685
    *file_buffer.pos++= (uchar) (bit_buffer >> 56);
 
2686
    *file_buffer.pos++= (uchar) (bit_buffer >> 48);
 
2687
    *file_buffer.pos++= (uchar) (bit_buffer >> 40);
 
2688
    *file_buffer.pos++= (uchar) (bit_buffer >> 32);
 
2689
#endif
 
2690
    *file_buffer.pos++= (uchar) (bit_buffer >> 24);
 
2691
    *file_buffer.pos++= (uchar) (bit_buffer >> 16);
 
2692
    *file_buffer.pos++= (uchar) (bit_buffer >> 8);
 
2693
    *file_buffer.pos++= (uchar) (bit_buffer);
 
2694
 
 
2695
    if (bits != 8 * sizeof(value))
 
2696
      value&= (((uint64_t) 1) << bits) - 1;
 
2697
    if (file_buffer.pos >= file_buffer.end)
 
2698
      VOID(flush_buffer(~ (ulong) 0));
 
2699
    file_buffer.bits=(int) (BITS_SAVED - bits);
 
2700
    file_buffer.bitbucket= value << (BITS_SAVED - bits);
 
2701
  }
 
2702
  return;
 
2703
}
 
2704
 
 
2705
        /* Flush bits in bit_buffer to buffer */
 
2706
 
 
2707
static void flush_bits(void)
 
2708
{
 
2709
  int bits;
 
2710
  uint64_t bit_buffer;
 
2711
 
 
2712
  bits= file_buffer.bits & ~7;
 
2713
  bit_buffer= file_buffer.bitbucket >> bits;
 
2714
  bits= BITS_SAVED - bits;
 
2715
  while (bits > 0)
 
2716
  {
 
2717
    bits-= 8;
 
2718
    *file_buffer.pos++= (uchar) (bit_buffer >> bits);
 
2719
  }
 
2720
  if (file_buffer.pos >= file_buffer.end)
 
2721
    VOID(flush_buffer(~ (ulong) 0));
 
2722
  file_buffer.bits= BITS_SAVED;
 
2723
  file_buffer.bitbucket= 0;
 
2724
}
 
2725
 
 
2726
 
 
2727
/****************************************************************************
 
2728
** functions to handle the joined files
 
2729
****************************************************************************/
 
2730
 
 
2731
static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length,
 
2732
                      ha_checksum crc)
 
2733
{
 
2734
  MYISAM_SHARE *share=isam_file->s;
 
2735
  uint options=mi_uint2korr(share->state.header.options);
 
2736
  uint key;
 
2737
 
 
2738
  options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
 
2739
  mi_int2store(share->state.header.options,options);
 
2740
 
 
2741
  share->state.state.data_file_length=new_length;
 
2742
  share->state.state.del=0;
 
2743
  share->state.state.empty=0;
 
2744
  share->state.dellink= HA_OFFSET_ERROR;
 
2745
  share->state.split=(ha_rows) mrg->records;
 
2746
  share->state.version=(ulong) time((time_t*) 0);
 
2747
  if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
 
2748
  {
 
2749
    /*
 
2750
      Some indexes are disabled, cannot use current key_file_length value
 
2751
      as an estimate of upper bound of index file size. Use packed data file 
 
2752
      size instead.
 
2753
    */
 
2754
    share->state.state.key_file_length= new_length;
 
2755
  }
 
2756
  /*
 
2757
    If there are no disabled indexes, keep key_file_length value from 
 
2758
    original file so "myisamchk -rq" can use this value (this is necessary 
 
2759
    because index size cannot be easily calculated for fulltext keys)
 
2760
  */
 
2761
  mi_clear_all_keys_active(share->state.key_map);
 
2762
  for (key=0 ; key < share->base.keys ; key++)
 
2763
    share->state.key_root[key]= HA_OFFSET_ERROR;
 
2764
  for (key=0 ; key < share->state.header.max_block_size_index ; key++)
 
2765
    share->state.key_del[key]= HA_OFFSET_ERROR;
 
2766
  isam_file->state->checksum=crc;       /* Save crc here */
 
2767
  share->changed=1;                     /* Force write of header */
 
2768
  share->state.open_count=0;
 
2769
  share->global_changed=0;
 
2770
  (void)ftruncate(share->kfile, share->base.keystart);
 
2771
  if (share->base.keys)
 
2772
    isamchk_neaded=1;
 
2773
  return(mi_state_info_write(share->kfile,&share->state,1+2));
 
2774
}
 
2775
 
 
2776
 
 
2777
static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length,
 
2778
                          ha_checksum crc)
 
2779
{
 
2780
  MI_STATE_INFO state;
 
2781
  MI_INFO *isam_file=mrg->file[0];
 
2782
  uint options;
 
2783
 
 
2784
  state= isam_file->s->state;
 
2785
  options= (mi_uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
 
2786
            HA_OPTION_READ_ONLY_DATA);
 
2787
  mi_int2store(state.header.options,options);
 
2788
  state.state.data_file_length=new_length;
 
2789
  state.state.del=0;
 
2790
  state.state.empty=0;
 
2791
  state.state.records=state.split=(ha_rows) mrg->records;
 
2792
  /* See comment above in save_state about key_file_length handling. */
 
2793
  if (mrg->src_file_has_indexes_disabled)
 
2794
  {
 
2795
    isam_file->s->state.state.key_file_length=
 
2796
      max(isam_file->s->state.state.key_file_length, new_length);
 
2797
  }
 
2798
  state.dellink= HA_OFFSET_ERROR;
 
2799
  state.version=(ulong) time((time_t*) 0);
 
2800
  mi_clear_all_keys_active(state.key_map);
 
2801
  state.state.checksum=crc;
 
2802
  if (isam_file->s->base.keys)
 
2803
    isamchk_neaded=1;
 
2804
  state.changed=STATE_CHANGED | STATE_NOT_ANALYZED; /* Force check of table */
 
2805
  return (mi_state_info_write(file,&state,1+2));
 
2806
}
 
2807
 
 
2808
 
 
2809
/* reset for mrg_rrnd */
 
2810
 
 
2811
static void mrg_reset(PACK_MRG_INFO *mrg)
 
2812
{
 
2813
  if (mrg->current)
 
2814
  {
 
2815
    mi_extra(*mrg->current, HA_EXTRA_NO_CACHE, 0);
 
2816
    mrg->current=0;
 
2817
  }
 
2818
}
 
2819
 
 
2820
static int mrg_rrnd(PACK_MRG_INFO *info,uchar *buf)
 
2821
{
 
2822
  int error;
 
2823
  MI_INFO *isam_info;
 
2824
  my_off_t filepos;
 
2825
 
 
2826
  if (!info->current)
 
2827
  {
 
2828
    isam_info= *(info->current=info->file);
 
2829
    info->end=info->current+info->count;
 
2830
    mi_reset(isam_info);
 
2831
    mi_extra(isam_info, HA_EXTRA_CACHE, 0);
 
2832
    filepos=isam_info->s->pack.header_length;
 
2833
  }
 
2834
  else
 
2835
  {
 
2836
    isam_info= *info->current;
 
2837
    filepos= isam_info->nextpos;
 
2838
  }
 
2839
 
 
2840
  for (;;)
 
2841
  {
 
2842
    isam_info->update&= HA_STATE_CHANGED;
 
2843
    if (!(error=(*isam_info->s->read_rnd)(isam_info,(uchar*) buf,
 
2844
                                          filepos, 1)) ||
 
2845
        error != HA_ERR_END_OF_FILE)
 
2846
      return (error);
 
2847
    mi_extra(isam_info,HA_EXTRA_NO_CACHE, 0);
 
2848
    if (info->current+1 == info->end)
 
2849
      return(HA_ERR_END_OF_FILE);
 
2850
    info->current++;
 
2851
    isam_info= *info->current;
 
2852
    filepos=isam_info->s->pack.header_length;
 
2853
    mi_reset(isam_info);
 
2854
    mi_extra(isam_info,HA_EXTRA_CACHE, 0);
 
2855
  }
 
2856
}
 
2857
 
 
2858
 
 
2859
static int mrg_close(PACK_MRG_INFO *mrg)
 
2860
{
 
2861
  uint i;
 
2862
  int error=0;
 
2863
  for (i=0 ; i < mrg->count ; i++)
 
2864
    error|=mi_close(mrg->file[i]);
 
2865
  if (mrg->free_file)
 
2866
    my_free((uchar*) mrg->file,MYF(0));
 
2867
  return error;
 
2868
}