YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/* Pack MARIA file */
#ifndef USE_MY_FUNC #define USE_MY_FUNC /* We need at least my_malloc */ #endif
#define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */ #define HEAD_LENGTH 32 #define ALLOWED_JOIN_DIFF 256/* Diff allowed to join trees */
typedefstruct st_isam_mrg {
MARIA_HA **file,**current,**end;
uint free_file;
uint count;
uint min_pack_length; /* Theese is used by packed data */
uint max_pack_length;
uint ref_length;
uint max_blob_length;
my_off_t records; /* true if at least one source file has at least one disabled index */
my_bool src_file_has_indexes_disabled;
} PACK_MRG_INFO;
staticstruct my_option my_long_options[] =
{ #ifdef __NETWARE__
{"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif
{"backup", 'b', "Make a backup of the table as table_name.OLD.",
&backup, &backup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"character-sets-dir", OPT_CHARSETS_DIR_MP, "Directory where character sets are.", (char**) &charsets_dir,
(char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"datadir", 'h', "Path for control file (and logs if --logdir not used).",
(char**) &maria_data_root, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"force", 'f', "Force packing of table even if it gets bigger or if tempfile exists.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ "ignore-control-file", 0, "Ignore the control file",
(uchar**)&opt_ignore_control_file, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"join", 'j', "Join all given tables into 'new_table_name'. All tables MUST have identical layouts.",
&join_table, &join_table, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ "require-control-file", 0, "Abort if cannot find control file",
(uchar**)&opt_require_control_file, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"silent", 's', "Be more silent.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"tmpdir", 'T', "Use temporary directory to store temporary table.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"test", 't', "Don't pack table, only test packing it.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Write info about progress and packing result. Use many -v for more verbosity!", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"wait", 'w', "Wait and retry if table is in use.", &opt_wait,
&opt_wait, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
staticvoid usage(void)
{
print_version();
puts("Copyright 2002-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
puts("and you are welcome to modify and redistribute it under the GPL license\n");
puts("Pack a Aria-table to take much less space.");
puts("Keys are not updated, you must run aria_chk -rq on the index (.MAI) file");
puts("afterwards to update the keys.");
puts("You should give the .MAI file as the filename argument.");
puts("To unpack a packed table, run aria_chk -u on the table");
switch(opt->id) { #ifdef __NETWARE__ case OPT_AUTO_CLOSE:
setscreenmode(SCR_AUTOCLOSE_ON_EXIT); break; #endif case'f':
force_pack= 1;
tmpfile_createflag= O_RDWR | O_TRUNC; break; case's':
write_loop= verbose= 0;
silent= 1; break; case't':
test_only= 1; /* Avoid to reset 'verbose' if it was already set > 1. */ if (! verbose)
verbose= 1; break; case'T':
length= (uint) (strmov(tmp_dir, argument) - tmp_dir); if (length != dirname_length(tmp_dir))
{
tmp_dir[length]=FN_LIBCHAR;
tmp_dir[length+1]=0;
} break; case'v':
verbose++; /* Allow for selecting the level of verbosity. */
silent= 0; break; case'#':
DBUG_PUSH(argument ? argument : "d:t:o,/tmp/aria_pack.trace"); break; case'V':
print_version();
my_exit(0); break; case'I': case'?':
usage();
my_exit(0);
} return0;
}
/* reads options */ /* Initiates DEBUG - but no debugging here ! */
staticvoid get_options(int *argc,char ***argv)
{ int ho_error;
my_progname= argv[0][0]; if (isatty(fileno(stdout)))
write_loop=1;
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
my_exit(ho_error);
if (!*argc)
{
usage();
my_exit(1);
} if (join_table)
{
backup=0; /* Not needed */
tmp_dir[0]=0;
} return;
}
staticvoid print_error(int error, constchar *filename)
{ switch (error) { case HA_ERR_CRASHED:
fprintf(stderr, "'%s' doesn't have a correct index definition. You need to recreate it before you can do a repair",filename); break; case HA_ERR_NOT_A_TABLE:
fprintf(stderr, "'%s' is not a Aria table",filename); break; case HA_ERR_CRASHED_ON_USAGE:
fprintf(stderr, "'%s' is marked as crashed",filename); break; case HA_ERR_CRASHED_ON_REPAIR:
fprintf(stderr, "'%s' is marked as crashed after last repair",filename); break; case HA_ERR_OLD_FILE:
fprintf(stderr, "'%s' has transactions newer than registered in control file. If this is ok, please re-run with --ignore-control-file", filename); break; case HA_ERR_NEW_FILE:
fprintf(stderr, "'%s' uses new features not supported by this version of the Aria library", filename); break; case HA_ERR_END_OF_FILE:
fprintf(stderr, "Couldn't read complete header from '%s'", filename); break; case EAGAIN:
fprintf(stderr, "'%s' is locked. Use -w to wait until unlocked",filename); break; case ENOENT:
fprintf(stderr, "File '%s' doesn't exist",filename); break; case EACCES:
fprintf(stderr, "You don't have permission to use '%s'", filename); break; default:
fprintf(stderr, "%d when opening Aria table '%s'", error, filename); break;
}
fputc('\n',stderr);
}
if (!(isam_file=maria_open(name, mode, HA_OPEN_IGNORE_MOVED_STATE |
(opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
HA_OPEN_ABORT_IF_LOCKED), 0)))
{
print_error(my_errno, name);
DBUG_RETURN(0);
}
share=isam_file->s; if (share->options & HA_OPTION_COMPRESS_RECORD && !join_table)
{ if (!force_pack)
{
fprintf(stderr, "%s is already compressed\n", name);
maria_close(isam_file);
DBUG_RETURN(0);
} if (verbose)
puts("Recompressing already compressed table");
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifying it */
} if (! force_pack && share->state.state.records != 0 &&
(share->state.state.records <= 1 ||
share->state.state.data_file_length < 1024))
{
fprintf(stderr, "%s is too small to compress\n", name);
maria_close(isam_file);
DBUG_RETURN(0);
}
maria_lock_database(isam_file,F_WRLCK);
maria_ignore_trids(isam_file);
DBUG_RETURN(isam_file);
}
static my_bool open_maria_files(PACK_MRG_INFO *mrg,char **names,uint count)
{
uint i,j;
mrg->count=0;
mrg->current=0;
mrg->file=(MARIA_HA**) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(MARIA_HA*)*count,MYF(MY_FAE));
mrg->free_file=1;
mrg->src_file_has_indexes_disabled= 0; for (i=0; i < count ; i++)
{ if (!(mrg->file[i]=open_maria_file(names[i],O_RDONLY))) goto error;
mrg->src_file_has_indexes_disabled|=
! maria_is_all_keys_active(mrg->file[i]->s->state.key_map,
mrg->file[i]->s->base.keys);
} /* Check that files are identical */ for (j=0 ; j < count-1 ; j++)
{
MARIA_COLUMNDEF *m1,*m2,*end; if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields) goto diff_file;
m1=mrg->file[j]->s->columndef;
end=m1+mrg->file[j]->s->base.fields;
m2=mrg->file[j+1]->s->columndef; for ( ; m1 != end ; m1++,m2++)
{ if (m1->type != m2->type || m1->length != m2->length) goto diff_file;
}
}
mrg->count=count; return0;
diff_file:
fprintf(stderr, "%s: Tables '%s' and '%s' are not identical\n",
my_progname, names[j], names[j+1]);
error: while (i--)
maria_close(mrg->file[i]);
my_free(mrg->file); return1;
}
isam_file=mrg->file[0]; /* Take this as an example */
share=isam_file->s;
new_file=join_maria_file= -1;
trees=fields=0;
huff_trees=0;
huff_counts=0;
maria_block_size= isam_file->s->block_size;
/* Create temporary or join file */ if (backup)
fn_format(org_name,isam_file->s->open_file_name.str, "",MARIA_NAME_DEXT, 2); else
fn_format(org_name,isam_file->s->open_file_name.str, "",MARIA_NAME_DEXT, 2+4+16);
if (multi_init_pagecache(&maria_pagecaches, 1, MARIA_MIN_PAGE_CACHE_SIZE, 0, 0, maria_block_size, 0, MY_WME))
{
fprintf(stderr, "Can't initialize page cache\n"); goto err;
} /* The pagecache is initialized. Update the table pagecaches pointers */ for (i=0 ; i < mrg->count ; i++)
ma_change_pagecache(mrg->file[i]);
if (!test_only && result_table)
{ /* Make a new indexfile based on first file in list */
uint length;
uchar *buff;
strmov(org_name,result_table); /* Fix error messages */
fn_format(new_name,result_table,"",MARIA_NAME_IEXT,2); if ((join_maria_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
< 0) goto err;
length=(uint) share->base.keystart; if (!(buff= (uchar*) my_malloc(PSI_NOT_INSTRUMENTED, length, MYF(MY_WME)))) goto err; if (my_pread(share->kfile.file, buff, length, 0L, MYF(MY_WME | MY_NABP)) ||
my_write(join_maria_file,buff,length,
MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
{
my_free(buff); goto err;
}
my_free(buff);
fn_format(new_name,result_table,"",MARIA_NAME_DEXT,2);
} elseif (!tmp_dir[0])
make_new_name(new_name,org_name); else
fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4); if (!test_only &&
(new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0) goto err;
/* Start calculating statistics */
mrg->records=0; for (i=0 ; i < mrg->count ; i++)
mrg->records+=mrg->file[i]->s->state.state.records;
if (huff_trees)
{ for (i=0 ; i < trees ; i++)
{ if (huff_trees[i].element_buffer)
my_free(huff_trees[i].element_buffer); if (huff_trees[i].code)
my_free(huff_trees[i].code);
}
my_free(huff_trees);
} if (huff_counts)
{ for (i=0 ; i < fields ; i++)
{ if (huff_counts[i].tree_buff)
{
my_free(huff_counts[i].tree_buff);
delete_tree(&huff_counts[i].int_tree, 0);
}
}
my_free(huff_counts);
}
delete_queue(&queue); /* This is safe to free */ return;
}
/* Read through old file and gather some statistics */
/* Check how to calculate checksum */ if (mrg->file[0]->s->data_file_type == STATIC_RECORD)
calc_checksum= _ma_static_checksum; else
calc_checksum= _ma_checksum;
mrg_reset(mrg); while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
{
ulong tot_blob_length=0; if (! error)
{ /* glob_crc is a checksum over all bytes of all records. */
glob_crc+= (*calc_checksum)(mrg->file[0],record);
/* Count the incidence of values separately for every column. */ for (pos=record + null_bytes, count=huff_counts ;
count < end_count ;
count++,
pos=next_pos)
{
next_pos=end_pos=(start_pos=pos)+count->field_length;
WARNING:Atfirst,weinsertapointerintotherecordbuffer asthekeyforthetree.Ifwegotanewdistinctvalue,which isreallyinsertedintothetree,insteadofbeingcounted only,wewillcopythecolumnvaluefromtherecordbufferto 'tree_buff'andadjustthekeypointerofthetreeaccordingly.
*/ if (count->tree_buff)
{
global_count=count; if (!(element=tree_insert(&count->int_tree,pos, 0,
count->int_tree.custom_arg)) ||
(element->count == 1 &&
(count->tree_buff + tree_buff_length <
count->tree_pos + count->field_length)) ||
(count->int_tree.elements_in_tree > IS_OFFSET / 2) ||
(count->field_length == 1 &&
count->int_tree.elements_in_tree > 1))
{
delete_tree(&count->int_tree, 0);
my_free(count->tree_buff);
count->tree_buff=0;
} else
{ /* Iftree_insert()succeeds,iteithercreatesanewelement orincrementsthecounterofanexistingelement.
*/ if (element->count == 1)
{ /* Copy the new column value into 'tree_buff'. */
memcpy(count->tree_pos,pos,(size_t) count->field_length); /* Adjust the key pointer in the tree. */
tree_set_pointer(element,count->tree_pos); /* Point behind the last column value so far. */
count->tree_pos+=count->field_length;
}
}
}
/* Save character counters and space-counts and zero-field-counts */ if (count->field_type == FIELD_NORMAL ||
count->field_type == FIELD_SKIP_ENDSPACE)
{ /* Ignore trailing space. */ for ( ; end_pos > pos ; end_pos--) if (end_pos[-1] != ' ') break; /* Empty fields are just counted. Go to the next record. */ if (end_pos == pos)
{
count->empty_fields++;
count->max_zero_fill=0; continue;
} /* Countthetotalofalltrailingspacesandthenumberof shorttrailingspaces.Rememberthelongesttrailingspace.
*/
length= (uint) (next_pos-end_pos);
count->tot_end_space+=length; if (length < 8)
count->end_space[length]++; if (count->max_end_space < length)
count->max_end_space = length;
}
if (count->field_type == FIELD_NORMAL ||
count->field_type == FIELD_SKIP_PRESPACE)
{ /* Ignore leading space. */ for (pos=start_pos; pos < end_pos ; pos++) if (pos[0] != ' ') break; /* Empty fields are just counted. Go to the next record. */ if (end_pos == pos)
{
count->empty_fields++;
count->max_zero_fill=0; continue;
} /* Countthetotalofallleadingspacesandthenumberof shortleadingspaces.Rememberthelongestleadingspace.
*/
length= (uint) (pos-start_pos);
count->tot_pre_space+=length; if (length < 8)
count->pre_space[length]++; if (count->max_pre_space < length)
count->max_pre_space = length;
}
/* Evaluate 'max_zero_fill' for short fields. */ if (count->field_length <= 8 &&
(count->field_type == FIELD_NORMAL ||
count->field_type == FIELD_SKIP_ZERO))
{
uint i; /* Zero fields are just counted. Go to the next record. */ if (!memcmp(start_pos, zero_string, count->field_length))
{
count->zero_fields++; continue;
} /* max_zero_fillstartswithfield_length.Itisdecreasedevery timeashorter"zerotrailer"isfound.Itissettozerowhen anemptyfieldisfound(seeabove).Thissuggeststhatthe variableshouldbecalled'min_zero_fill'.
*/ for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ;
i++) ; if (i < count->max_zero_fill)
count->max_zero_fill=i;
}
/* Ignore zero fields and check fields. */ if (count->field_type == FIELD_ZERO ||
count->field_type == FIELD_CHECK) continue;
DBUG_PRINT("info", ("Found the following number of incidents " "of the uchar codes:")); if (verbose >= 2)
printf("Found the following number of incidents " "of the uchar codes:\n"); for (count= huff_counts ; count < end_count; count++)
{
uint idx;
my_off_t total_count; char llbuf[32];
/* Check for zero-filled records (in this column), or zero records. */ if (huff_counts->zero_fields || ! records)
{
my_off_t old_space_count; /* Ifthereareonlyzerofilledrecords(inthiscolumn), ornorecordsatall,wearedone.
*/ if (huff_counts->zero_fields == records)
{
huff_counts->field_type= FIELD_ZERO;
huff_counts->bytes_packed=0;
huff_counts->counts[0]=0; goto found_pack;
} /* Remeber the number of significant spaces. */
old_space_count=huff_counts->counts[' ']; /* Add all leading and trailing spaces. */
huff_counts->counts[' ']+= (huff_counts->tot_end_space +
huff_counts->tot_pre_space +
huff_counts->empty_fields *
huff_counts->field_length); /* Check, what the compressed length of this would be. */
old_length=calc_packed_length(huff_counts,0)+records/8; /* Get the number of zero bytes. */
length=huff_counts->zero_fields*huff_counts->field_length; /* Add it to the counts. */
huff_counts->counts[0]+=length; /* Check, what the compressed length of this would be. */
new_length=calc_packed_length(huff_counts,0); /* If the compression without the zeroes would be shorter, we are done. */ if (old_length < new_length && huff_counts->field_length > 1)
{
huff_counts->field_type=FIELD_SKIP_ZERO;
huff_counts->counts[0]-=length;
huff_counts->bytes_packed=old_length- records/8; goto found_pack;
} /* Remove the insignificant spaces, but keep the zeroes. */
huff_counts->counts[' ']=old_space_count;
} /* Check, what the compressed length of this column would be. */
huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
/* Ifthereareenoughemptyrecords(inthiscolumn), treatingthemspeciallymaypayoff.
*/ if (huff_counts->empty_fields)
{ if (huff_counts->field_length > 2 &&
huff_counts->empty_fields + (records - huff_counts->empty_fields)*
(1+max_bit(MY_MAX(huff_counts->max_pre_space,
huff_counts->max_end_space))) <
records * max_bit(huff_counts->field_length))
{
huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
} else
{
length=huff_counts->empty_fields*huff_counts->field_length; if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
{
huff_counts->tot_end_space+=length;
huff_counts->max_end_space=huff_counts->field_length; if (huff_counts->field_length < 8)
huff_counts->end_space[huff_counts->field_length]+=
huff_counts->empty_fields;
} if (huff_counts->tot_pre_space)
{
huff_counts->tot_pre_space+=length;
huff_counts->max_pre_space=huff_counts->field_length; if (huff_counts->field_length < 8)
huff_counts->pre_space[huff_counts->field_length]+=
huff_counts->empty_fields;
}
}
}
/* Ifthereareenoughtrailingspaces(inthiscolumn), treatingthemspeciallymaypayoff.
*/ if (huff_counts->tot_end_space)
{
huff_counts->counts[' ']+=huff_counts->tot_pre_space; if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
huff_counts->end_space,
huff_counts->tot_end_space,FIELD_SKIP_ENDSPACE)) goto found_pack;
huff_counts->counts[' ']-=huff_counts->tot_pre_space;
}
/* Ifthereareenoughleadingspaces(inthiscolumn), treatingthemspeciallymaypayoff.
*/ if (huff_counts->tot_pre_space)
{ if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
huff_counts->pre_space,
huff_counts->tot_pre_space,FIELD_SKIP_PRESPACE)) goto found_pack;
}
if (!(huff_tree=(HUFF_TREE*) my_malloc(PSI_NOT_INSTRUMENTED,
trees*sizeof(HUFF_TREE), MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(0);
for (tree=0 ; tree < trees ; tree++)
{ if (make_huff_tree(huff_tree+tree,huff_counts+tree))
{ while (tree--)
my_free(huff_tree[tree].element_buffer);
my_free(huff_tree);
DBUG_RETURN(0);
}
}
DBUG_RETURN(huff_tree);
}
first=last=0; if (huff_counts->tree_buff)
{ /* Calculate the number of distinct values in tree_buff. */
found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
huff_counts->field_length;
first=0; last=found-1;
} else
{ /* Count the number of uchar codes found in the column. */ for (i=found=0 ; i < 256 ; i++)
{ if (huff_counts->counts[i])
{ if (! found++)
first=i;
last=i;
}
} if (found < 2)
found=2;
}
/* When using 'tree_buff' we can have more that 256 values. */ if (queue.max_elements < found)
{
delete_queue(&queue); if (init_queue(&queue,found, 0, 0, compare_huff_elements, 0, 0, 0)) return -1;
}
/* Allocate or reallocate an element buffer for the Huffman tree. */ if (!huff_tree->element_buffer)
{ if (!(huff_tree->element_buffer=
(HUFF_ELEMENT*) my_malloc(PSI_NOT_INSTRUMENTED,
found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME)))) return1;
} else
{
HUFF_ELEMENT *temp; if (!(temp= (HUFF_ELEMENT*) my_realloc(PSI_NOT_INSTRUMENTED,
(uchar*) huff_tree->element_buffer, found*2*sizeof(HUFF_ELEMENT), MYF(MY_WME)))) return1;
huff_tree->element_buffer=temp;
}
/* The Huffman algorithm. */
bytes_packed=0; bits_packed=0; for (i=1 ; i < found ; i++)
{ /* Popthetopelementfromthequeue(theonewiththeleastincidence). Poppingfromapriorityqueueincludesare-orderingofthequeue, togetthenextleastincidenceelementtothetop.
*/
a=(HUFF_ELEMENT*) queue_remove_top(&queue); /* Copy the next least incidence element */
b=(HUFF_ELEMENT*) queue_top(&queue); /* Get a new element from the element buffer. */
new_huff_el=huff_tree->element_buffer+found+i; /* The new element gets the sum of the two least incidence elements. */
new_huff_el->count=a->count+b->count; /* TheHuffmanalgorithmassignsanotherbittothecodeforabyte everytimethatbytesincidenceiscombined(directlyorindirectly) toanewelementasoneofthetwoleastincidenceelements. Thismeansthatonemorebitperincidenceofthatucharisrequired intheresultingfile.Soweaddthenewcombinedincidenceasthe numberofbitsbywhichtheresultgrows.
*/
bits_packed+=(uint) (new_huff_el->count & 7);
bytes_packed+=new_huff_el->count/8; /* The new element points to its children, lesser in left. */
new_huff_el->a.nod.left=a;
new_huff_el->a.nod.right=b; /* Replacethecopiedtopelementbythenewelementandre-orderthe queue.
*/
queue_top(&queue)= (uchar*) new_huff_el;
queue_replace_top(&queue);
}
huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8; return0;
}
Insteadofusingqueue_insert(),wejustcopythereferencesinto thebufferofthepriorityqueue.Weinsertinucharvalueorder,but theorderisinfactirrelevanthere.Wewillestablishthecorrect orderlater.
*/
first=last=0; for (i=found=0 ; i < 256 ; i++)
{ if (huff_counts->counts[i])
{ if (! found++)
first=i;
last=i; /* We start with root[1], which is the queues top element. */
queue.root[found]=(uchar*) &huff_counts->counts[i];
}
} if (!found)
DBUG_RETURN(0); /* Empty tree */ /* Ifthereisonlyasingleucharvalueinthisfieldinallrecords, addasecondelementwithzeroincidence.Thisisrequiredtoenter theloop,whichfollowstheHuffmanalgorithm.
*/ if (found < 2)
queue.root[++found]=(uchar*) &huff_counts->counts[last ? 0 : 1];
/* Make a queue from the queue buffer. */
queue.elements=found;
bytes_packed=0; bits_packed=0; /* Add the length of the coding table, which would become part of the file. */ if (add_tree_lenght)
bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
(max_bit(found-1)+1+1)*(found-2) +7)/8;
/* The Huffman algorithm. */ for (i=0 ; i < found-1 ; i++)
{
my_off_t *a;
my_off_t *b;
HUFF_ELEMENT *new_huff_el;
/* Popthetopelementfromthequeue(theonewiththeleast incidence).Poppingfromapriorityqueueincludesare-ordering ofthequeue,togetthenextleastincidenceelementtothetop.
*/
a= (my_off_t*) queue_remove_top(&queue); /* Copy the next least incidence element. */
b= (my_off_t*) queue_top(&queue); /* Create a new element in a local (automatic) buffer. */
new_huff_el= element_buffer + i; /* The new element gets the sum of the two least incidence elements. */
new_huff_el->count= *a + *b; /* TheHuffmanalgorithmassignsanotherbittothecodeforabyte everytimethatbytesincidenceiscombined(directlyorindirectly) toanewelementasoneofthetwoleastincidenceelements. Thismeansthatonemorebitperincidenceofthatucharisrequired intheresultingfile.Soweaddthenewcombinedincidenceasthe numberofbitsbywhichtheresultgrows.
*/
bits_packed+=(uint) (new_huff_el->count & 7);
bytes_packed+=new_huff_el->count/8; /* Replacethecopiedtopelementbythenewelementandre-orderthe queue.Thissuccessivelyreplacesthereferencestocountsby referencestoHUFF_ELEMENTs.
*/
queue_top(&queue)= (uchar*) new_huff_el;
queue_replace_top(&queue);
}
DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
}
/* Remove trees that don't give any compression */
/* Find the highest number of elements in the trees. */ for (i=length=0 ; i < trees ; i++) if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
length=huff_tree[i].elements; /* Allocateabufferforpackingadecodetree.Twonumbersperelement (leftchildandrightchild).
*/ if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
{
my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2); return0;
}
DBUG_PRINT("info", (" ")); if (verbose >= 2)
printf("\n");
tree_no= 0;
intervall_length=0; for (elements=0; trees-- ; huff_tree++)
{ /* Skip columns that have been joined with other columns. */ if (huff_tree->tree_number == 0) continue; /* Deleted tree */
tree_no++;
DBUG_PRINT("info", (" ")); if (verbose >= 3)
printf("\n"); /* Count the total number of elements (byte codes or column values). */
elements+=huff_tree->elements;
huff_tree->max_offset=2; /* Build a tree of offsets and codes for decoding in 'packed_tree'. */ if (huff_tree->elements <= 1)
offset=packed_tree; else
offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
/* This should be the same as 'length' above. */
huff_tree->offset_bits=max_bit(huff_tree->max_offset);
/* Sincewecheckthisduringcollectingthedistinctcolumnvalues, thisshouldneverhappen.
*/ if (huff_tree->max_offset >= IS_OFFSET)
{ /* This should be impossible */
fprintf(stderr, "Tree offset got too big: %d, aborted\n",
huff_tree->max_offset);
my_afree(packed_tree); return0;
}
DBUG_PRINT("info", ("pos: %lu elements: %u tree-elements: %lu " "char_bits: %u\n",
(ulong) (file_buffer.pos - file_buffer.buffer),
huff_tree->elements, (ulong) (offset - packed_tree),
huff_tree->char_bits)); if (!huff_tree->counts->tree_buff)
{ /* We do a uchar compression on this column. Mark with bit 0. */
write_bits(0,1);
write_bits(huff_tree->min_chr,8);
write_bits(huff_tree->elements,9);
write_bits(huff_tree->char_bits,5);
write_bits(huff_tree->offset_bits,5);
int_length=0;
} else
{
int_length=(uint) (huff_tree->counts->tree_pos -
huff_tree->counts->tree_buff); /* We have distinct column values for this column. Mark with bit 1. */
write_bits(1,1);
write_bits(huff_tree->elements,15);
write_bits(int_length,16);
write_bits(huff_tree->char_bits,5);
write_bits(huff_tree->offset_bits,5);
intervall_length+=int_length;
}
DBUG_PRINT("info", ("tree: %2u elements: %4u char_bits: %2u " "offset_bits: %2u %s: %5u codelen: %2u",
tree_no, huff_tree->elements, huff_tree->char_bits,
huff_tree->offset_bits, huff_tree->counts->tree_buff ? "bufflen" : "min_chr", huff_tree->counts->tree_buff ?
int_length : huff_tree->min_chr, huff_tree->height)); if (verbose >= 2)
printf("tree: %2u elements: %4u char_bits: %2u offset_bits: %2u " "%s: %5u codelen: %2u\n", tree_no, huff_tree->elements,
huff_tree->char_bits, huff_tree->offset_bits,
huff_tree->counts->tree_buff ? "bufflen" : "min_chr",
huff_tree->counts->tree_buff ? int_length :
huff_tree->min_chr, huff_tree->height);
/* Check that the code tree length matches the element count. */
length=(uint) (offset-packed_tree); if (length != huff_tree->elements*2-2)
{
fprintf(stderr, "error: Huff-tree-length: %d != calc_length: %d\n",
length, huff_tree->elements * 2 - 2);
errors++; break;
}
for (i=0 ; i < length ; i++)
{ if (packed_tree[i] & IS_OFFSET)
write_bits(packed_tree[i] - IS_OFFSET+ (1 << huff_tree->offset_bits),
huff_tree->offset_bits+1); else
write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
DBUG_PRINT("info", ("tree[0x%04x]: %s0x%04x",
i, (packed_tree[i] & IS_OFFSET) ? " -> " : "", (packed_tree[i] & IS_OFFSET) ?
packed_tree[i] - IS_OFFSET + i : packed_tree[i])); if (verbose >= 3)
printf("tree[0x%04x]: %s0x%04x\n",
i, (packed_tree[i] & IS_OFFSET) ? " -> " : "",
(packed_tree[i] & IS_OFFSET) ?
packed_tree[i] - IS_OFFSET + i : packed_tree[i]);
}
flush_bits();
Thecurrentelementisalwaysanodewithtwochilds.Goleftfirst.
*/ if (!element->a.nod.left->a.leaf.null)
{ /* Store the uchar code or the index of the column value. */
prev_offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
offset+=2;
} else
{ /* Recursivelytraversethetreetotheleft.Markitasanoffsetto anothertreenode(incontrasttoaucharcodeorcolumnvalueindex).
*/
prev_offset[0]= IS_OFFSET+2;
offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
}
/* Now, check the right child. */ if (!element->a.nod.right->a.leaf.null)
{ /* Store the uchar code or the index of the column value. */
prev_offset[1]=element->a.nod.right->a.leaf.element_nr; return offset;
} else
{ /* Recursivelytraversethetreetotheright.Markitasanoffsetto anothertreenode(incontrasttoaucharcodeorcolumnvalueindex).
*/
uint temp=(uint) (offset-prev_offset-1);
prev_offset[1]= IS_OFFSET+ temp; if (huff_tree->max_offset < temp)
huff_tree->max_offset = temp; return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
}
}
/* Get number of bits neaded to represent value */
options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
mi_int2store(share->state.header.options,options); /* Save the original file type of we have to undo the packing later */
share->state.header.org_data_file_type= share->state.header.data_file_type;
share->state.header.data_file_type= COMPRESSED_RECORD;
share->state.state.data_file_length=new_length;
share->state.state.del=0;
share->state.state.empty=0;
share->state.dellink= HA_OFFSET_ERROR;
share->state.split=(ha_rows) mrg->records;
share->state.version=(ulong) time((time_t*) 0); if (share->base.born_transactional)
share->state.create_rename_lsn= share->state.is_of_horizon=
share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS; if (! maria_is_all_keys_active(share->state.key_map, share->base.keys))
{ /* Someindexesaredisabled,cannotusecurrentkey_file_lengthvalue asanestimateofupperboundofindexfilesize.Usepackeddatafile sizeinstead.
*/
share->state.state.key_file_length= new_length;
} /* Iftherearenodisabledindexes,keepkey_file_lengthvaluefrom originalfileso"aria_chk-rq"canusethisvalue(thisisnecessary becauseindexsizecannotbeeasilycalculatedforfulltextkeys)
*/
maria_clear_all_keys_active(share->state.key_map); for (key=0 ; key < share->base.keys ; key++)
share->state.key_root[key]= HA_OFFSET_ERROR;
share->state.key_del= HA_OFFSET_ERROR;
share->state.state.checksum= crc; /* Save crc in file */
share->changed=1; /* Force write of header */
share->state.open_count=0;
share->global_changed=0;
my_chsize(share->kfile.file, share->base.keystart, 0, MYF(0)); if (share->base.keys)
isamchk_neaded=1;
DBUG_RETURN(_ma_state_info_write_sub(share->kfile.file,
&share->state,
MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
MA_STATE_INFO_WRITE_FULL_INFO));
}
state= isam_file->s->state;
options= (mi_uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
HA_OPTION_READ_ONLY_DATA);
mi_int2store(state.header.options,options); /* Save the original file type of we have to undo the packing later */
state.header.org_data_file_type= state.header.data_file_type;
state.header.data_file_type= COMPRESSED_RECORD;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.