summaryrefslogtreecommitdiff
path: root/storage/maria
diff options
context:
space:
mode:
authorunknown <monty@mysql.com/narttu.mysql.fi>2008-04-01 17:57:30 +0300
committerunknown <monty@mysql.com/narttu.mysql.fi>2008-04-01 17:57:30 +0300
commit3651e3285d11c42a77e332009155b96132e5ba6e (patch)
tree27698eaec5a94020dafa1c0870190cd4b1c5d7cf /storage/maria
parentc63e18f43c1054db92c798e54ba9520fc16ea607 (diff)
downloadmariadb-git-3651e3285d11c42a77e332009155b96132e5ba6e.tar.gz
Merge of changes in MyISAM since December 16 -> April 1
Fixes bugs: Bug#28837 MyISAM storage engine error (134) doing delete with self-join Bug#31277 myisamchk --unpack corrupts table Bug#4692 DISABLE/ENABLE KEYS waste a space Bug#31305 myisam tables crash when they are near capacity BitKeeper/etc/ignore: added unittest/tmp/* mysql-test/r/maria.result: Moved missing tests from myisam.test to maria.test mysql-test/t/maria.test: Moved missing tests from myisam.test to maria.test storage/maria/ha_maria.cc: Merge of changes in MyISAM since December 16 -> April 1 Fixes bug in self join (Bug#28837: MyISAM storage engine error (134) doing delete with self-join) storage/maria/ha_maria.h: Merge of changes in MyISAM since December 16 -> April 1 storage/maria/ma_blockrec.c: Merge of changes in MyISAM since December 16 -> April 1 Fixes bug in self join (Bug#28837: MyISAM storage engine error (134) doing delete with self-join) The problem is that we may be using a cached key page with old information. Versioning will fix this storage/maria/ma_check.c: Merge of changes in MyISAM since December 16 -> April 1 This fixes a problem with pack_reclength not beeing big enough (Bug #31277 myisamchk --unpack corrupts table) BUG#4692 - DISABLE/ENABLE KEYS waste a space storage/maria/ma_delete.c: Indentation fixes storage/maria/ma_dynrec.c: Merge of changes in MyISAM since December 16 -> April 1 Fixes Bug#31305 myisam tables crash when they are near capacity. (This uses a simpler fix than in MyISAM by remembering the length of the current row) storage/maria/ma_ft_boolean_search.c: Merge of all changes from myisam/ft_boolean_search.c (This file had not been kept up to date) storage/maria/ma_open.c: Merge of changes in MyISAM since December 16 -> April 1 Calculate default_rec_buff_size more exact to be sure it's always big enough storage/maria/ma_packrec.c: Merge of changes in MyISAM since December 16 -> April 1 Update default_rec_buff_size to be big enough to hold one packed row Related to Bug#31277 myisamchk --unpack corrupts table storage/maria/ma_rnext_same.c: Indentation fixes storage/maria/ma_rt_index.c: Merge of changes in MyISAM since December 16 -> April 1 storage/maria/ma_rt_mbr.c: Merge of changes in MyISAM since December 16 -> April 1 (Added comment) storage/maria/ma_search.c: Merge of changes in MyISAM since December 16 -> April 1 (Added comment) storage/maria/ma_sort.c: Merge of changes in MyISAM since December 16 -> April 1 storage/maria/ma_statrec.c: Indentation fixes storage/maria/ma_test2.c: Indentation fixes storage/maria/maria_chk.c: Indentation fixes storage/maria/maria_pack.c: Merge of changes in MyISAM since December 16 -> April 1
Diffstat (limited to 'storage/maria')
-rw-r--r--storage/maria/ha_maria.cc20
-rw-r--r--storage/maria/ha_maria.h5
-rw-r--r--storage/maria/ma_blockrec.c4
-rw-r--r--storage/maria/ma_check.c209
-rw-r--r--storage/maria/ma_delete.c2
-rw-r--r--storage/maria/ma_dynrec.c57
-rw-r--r--storage/maria/ma_ft_boolean_search.c78
-rw-r--r--storage/maria/ma_open.c15
-rw-r--r--storage/maria/ma_packrec.c5
-rw-r--r--storage/maria/ma_rnext_same.c4
-rw-r--r--storage/maria/ma_rt_index.c18
-rw-r--r--storage/maria/ma_rt_mbr.c3
-rw-r--r--storage/maria/ma_search.c11
-rw-r--r--storage/maria/ma_sort.c6
-rw-r--r--storage/maria/ma_statrec.c4
-rw-r--r--storage/maria/ma_test2.c4
-rw-r--r--storage/maria/maria_chk.c6
-rw-r--r--storage/maria/maria_pack.c2
18 files changed, 329 insertions, 124 deletions
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 1ea42ac395a..47027356af4 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -273,6 +273,10 @@ static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type,
definition for further use in ma_create or for a check for underlying
table conformance in merge engine.
+ The caller needs to free *recinfo_out after use. Since *recinfo_out
+ and *keydef_out are allocated with a my_multi_malloc, *keydef_out
+ is freed automatically when *recinfo_out is freed.
+
RETURN VALUE
0 OK
# error code
@@ -1649,9 +1653,9 @@ int ha_maria::enable_indexes(uint mode)
param.testflag &= ~(T_REP_BY_SORT | T_QUICK);
error= (repair(thd, param, 0) != HA_ADMIN_OK);
/*
- If the standard repair succeeded, clear all error messages which
- might have been set by the first repair. They can still be seen
- with SHOW WARNINGS then.
+ If the standard repair succeeded, clear all error messages which
+ might have been set by the first repair. They can still be seen
+ with SHOW WARNINGS then.
*/
if (!error)
thd->clear_error();
@@ -1974,9 +1978,17 @@ int ha_maria::index_next_same(uchar * buf,
const uchar *key __attribute__ ((unused)),
uint length __attribute__ ((unused)))
{
+ int error;
DBUG_ASSERT(inited == INDEX);
ha_statistic_increment(&SSV::ha_read_next_count);
- int error= maria_rnext_same(file, buf);
+ /*
+ TODO: Delete this loop in Maria 1.5 as versioning will ensure this never
+ happens
+ */
+ do
+ {
+ error= maria_rnext_same(file,buf);
+ } while (error == HA_ERR_RECORD_DELETED);
table->status= error ? STATUS_NOT_FOUND : 0;
return error;
}
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
index 5818b2822d1..28acb8a93ca 100644
--- a/storage/maria/ha_maria.h
+++ b/storage/maria/ha_maria.h
@@ -157,6 +157,9 @@ public:
*engine_callback,
ulonglong *engine_data);
#endif
-
+ MARIA_HA *file_ptr(void)
+ {
+ return file;
+ }
static int implicit_commit(THD *thd);
};
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index f7a3e768f7f..c9b508626e5 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -4770,8 +4770,8 @@ int _ma_read_block_record(MARIA_HA *info, uchar *record,
if (!(data= get_record_position(buff, block_size, offset, &end_of_data)))
{
DBUG_PRINT("error", ("Wrong directory entry in data block"));
- my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
- DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
+ my_errno= HA_ERR_RECORD_DELETED; /* File crashed */
+ DBUG_RETURN(HA_ERR_RECORD_DELETED);
}
DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data));
}
diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c
index 5934bc1702a..9a7d189d291 100644
--- a/storage/maria/ma_check.c
+++ b/storage/maria/ma_check.c
@@ -489,7 +489,7 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
if ((!(param->testflag & T_SILENT)))
printf ("- check data record references index: %d\n",key+1);
- if (keyinfo->flag & HA_FULLTEXT)
+ if (keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL))
full_text_keys++;
if (share->state.key_root[key] == HA_OFFSET_ERROR)
{
@@ -1914,7 +1914,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
puts("- check record links");
}
- if (!(record= (uchar*) my_malloc(share->base.pack_reclength,MYF(0))))
+ if (!(record= (uchar*) my_malloc(share->base.default_rec_buff_size, MYF(0))))
{
_ma_check_print_error(param,"Not enough memory for record");
DBUG_RETURN(-1);
@@ -2199,6 +2199,121 @@ static int initialize_variables_for_repair(HA_CHECK *param,
}
+/**
+ @brief Drop all indexes
+
+ @param[in] param check parameters
+ @param[in] info MARIA_HA handle
+ @param[in] force if to force drop all indexes
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error
+
+ @note
+ Once allocated, index blocks remain part of the key file forever.
+ When indexes are disabled, no block is freed. When enabling indexes,
+ no block is freed either. The new indexes are create from new
+ blocks. (Bug #4692)
+
+ Before recreating formerly disabled indexes, the unused blocks
+ must be freed. There are two options to do this:
+ - Follow the tree of disabled indexes, add all blocks to the
+ deleted blocks chain. Would require a lot of random I/O.
+ - Drop all blocks by clearing all index root pointers and all
+ delete chain pointers and resetting key_file_length to the end
+ of the index file header. This requires to recreate all indexes,
+ even those that may still be intact.
+ The second method is probably faster in most cases.
+
+ When disabling indexes, MySQL disables either all indexes or all
+ non-unique indexes. When MySQL [re-]enables disabled indexes
+ (T_CREATE_MISSING_KEYS), then we either have "lost" blocks in the
+ index file, or there are no non-unique indexes. In the latter case,
+ maria_repair*() would not be called as there would be no disabled
+ indexes.
+
+ If there would be more unique indexes than disabled (non-unique)
+ indexes, we could do the first method. But this is not implemented
+ yet. By now we drop and recreate all indexes when repair is called.
+
+ However, there is an exception. Sometimes MySQL disables non-unique
+ indexes when the table is empty (e.g. when copying a table in
+ mysql_alter_table()). When enabling the non-unique indexes, they
+ are still empty. So there is no index block that can be lost. This
+ optimization is implemented in this function.
+
+ Note that in normal repair (T_CREATE_MISSING_KEYS not set) we
+ recreate all enabled indexes unconditonally. We do not change the
+ key_map. Otherwise we invert the key map temporarily (outside of
+ this function) and recreate the then "seemingly" enabled indexes.
+ When we cannot use the optimization, and drop all indexes, we
+ pretend that all indexes were disabled. By the inversion, we will
+ then recrate all indexes.
+*/
+
+static int maria_drop_all_indexes(HA_CHECK *param, MARIA_HA *info,
+ my_bool force)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_STATE_INFO *state= &share->state;
+ uint i;
+ DBUG_ENTER("maria_drop_all_indexes");
+
+ /*
+ If any of the disabled indexes has a key block assigned, we must
+ drop and recreate all indexes to avoid losing index blocks.
+
+ If we want to recreate disabled indexes only _and_ all of these
+ indexes are empty, we don't need to recreate the existing indexes.
+ */
+ if (!force && (param->testflag & T_CREATE_MISSING_KEYS))
+ {
+ DBUG_PRINT("repair", ("creating missing indexes"));
+ for (i= 0; i < share->base.keys; i++)
+ {
+ DBUG_PRINT("repair", ("index #: %u key_root: 0x%lx active: %d",
+ i, (long) state->key_root[i],
+ maria_is_key_active(state->key_map, i)));
+ if ((state->key_root[i] != HA_OFFSET_ERROR) &&
+ !maria_is_key_active(state->key_map, i))
+ {
+ /*
+ This index has at least one key block and it is disabled.
+ We would lose its block(s) if would just recreate it.
+ So we need to drop and recreate all indexes.
+ */
+ DBUG_PRINT("repair", ("nonempty and disabled: recreate all"));
+ break;
+ }
+ }
+ if (i >= share->base.keys)
+ goto end;
+
+ /*
+ We do now drop all indexes and declare them disabled. With the
+ T_CREATE_MISSING_KEYS flag, maria_repair*() will recreate all
+ disabled indexes and enable them.
+ */
+ maria_clear_all_keys_active(state->key_map);
+ DBUG_PRINT("repair", ("declared all indexes disabled"));
+ }
+
+ /* Clear index root block pointers. */
+ for (i= 0; i < share->base.keys; i++)
+ state->key_root[i]= HA_OFFSET_ERROR;
+
+ /* Drop the delete chain. */
+ share->state.key_del= HA_OFFSET_ERROR;
+
+ /* Reset index file length to end of index file header. */
+ info->state->key_file_length= share->base.keystart;
+
+end:
+ DBUG_RETURN(0);
+}
+
+
/*
Recover old table by reading each record and writing all keys
@@ -2225,7 +2340,6 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
char *name, my_bool rep_quick)
{
int error, got_error;
- uint i;
ha_rows start_records,new_header_length;
my_off_t del;
File new_file;
@@ -2317,9 +2431,9 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
goto err;
}
- if (!(sort_param.record= (uchar *) my_malloc((uint)
- share->base.pack_reclength,
- MYF(0))) ||
+ if (!(sort_param.record=
+ (uchar *) my_malloc((uint)
+ share->base.default_rec_buff_size, MYF(0))) ||
_ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
share->base.default_rec_buff_size))
{
@@ -2337,24 +2451,9 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
- /*
- Clear all keys. Note that all key blocks allocated until now remain
- "dead" parts of the key file. (Bug #4692)
- */
- for (i=0 ; i < share->base.keys ; i++)
- share->state.key_root[i]= HA_OFFSET_ERROR;
-
- /* Drop the delete chain. */
- share->state.key_del= HA_OFFSET_ERROR;
-
- /*
- If requested, activate (enable) all keys in key_map. In this case,
- all indexes will be (re-)built.
- */
if (param->testflag & T_CREATE_MISSING_KEYS)
maria_set_all_keys_active(share->state.key_map, share->base.keys);
-
- info->state->key_file_length=share->base.keystart;
+ maria_drop_all_indexes(param, info, TRUE);
maria_lock_memory(param); /* Everything is alloced */
@@ -2368,7 +2467,8 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
{
if (my_errno != HA_ERR_FOUND_DUPP_KEY)
goto err;
- DBUG_DUMP("record",(uchar*) sort_param.record,share->base.pack_reclength);
+ DBUG_DUMP("record", (uchar*) sort_param.record,
+ share->base.default_rec_buff_size);
_ma_check_print_warning(param,
"Duplicate key %2d for record at %10s against new record at %10s",
info->errkey+1,
@@ -3257,11 +3357,12 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
double *rec_per_key_part;
char llbuff[22];
MARIA_SORT_INFO sort_info;
- ulonglong key_map= share->state.key_map;
+ ulonglong key_map;
myf sync_dir= ((share->now_transactional && !share->temporary) ?
MY_SYNC_DIR : 0);
my_bool scan_inited= 0;
DBUG_ENTER("maria_repair_by_sort");
+ LINT_INIT(key_map);
got_error= 1;
new_file= -1;
@@ -3338,8 +3439,9 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
}
}
- if (!(sort_param.record=(uchar*) my_malloc((uint) share->base.pack_reclength,
- MYF(0))) ||
+ if (!(sort_param.record=
+ (uchar*) my_malloc((size_t) share->base.default_rec_buff_size,
+ MYF(0))) ||
_ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
share->base.default_rec_buff_size))
{
@@ -3347,16 +3449,14 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
goto err;
}
- if (!(param->testflag & T_CREATE_MISSING_KEYS))
+ /* Optionally drop indexes and optionally modify the key_map */
+ maria_drop_all_indexes(param, info, FALSE);
+ key_map= share->state.key_map;
+ if (param->testflag & T_CREATE_MISSING_KEYS)
{
- /* Clear the pointers to the given rows */
- for (i=0 ; i < share->base.keys ; i++)
- share->state.key_root[i]= HA_OFFSET_ERROR;
- share->state.key_del= HA_OFFSET_ERROR;
- info->state->key_file_length=share->base.keystart;
+ /* Invert the copied key_map to recreate all disabled indexes. */
+ key_map= ~key_map;
}
- else
- key_map= ~key_map; /* Create the missing keys */
param->read_cache.end_of_file= sort_info.filelength;
sort_param.wordlist=NULL;
@@ -3374,6 +3474,10 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
rec_per_key_part+=sort_param.keyinfo->keysegs, sort_param.key++)
{
sort_param.keyinfo=share->keyinfo+sort_param.key;
+ /*
+ Skip this index if it is marked disabled in the copied
+ (and possibly inverted) key_map.
+ */
if (! maria_is_key_active(key_map, sort_param.key))
{
/* Remember old statistics for key */
@@ -3381,6 +3485,8 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
(char*) (share->state.rec_per_key_part +
(uint) (rec_per_key_part - param->new_rec_per_key_part)),
sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
+ DBUG_PRINT("repair", ("skipping seemingly disabled index #: %u",
+ sort_param.key));
continue;
}
@@ -3492,6 +3598,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
sort_param.notnull : NULL),
(ulonglong) info->state->records);
maria_set_key_active(share->state.key_map, sort_param.key);
+ DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key));
if (_ma_flush_table_files_before_swap(param, info))
goto err;
@@ -3743,11 +3850,12 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
IO_CACHE new_data_cache; /* For non-quick repair. */
IO_CACHE_SHARE io_share;
MARIA_SORT_INFO sort_info;
- ulonglong key_map=share->state.key_map;
+ ulonglong key_map;
pthread_attr_t thr_attr;
myf sync_dir= ((share->now_transactional && !share->temporary) ?
MY_SYNC_DIR : 0);
DBUG_ENTER("maria_repair_parallel");
+ LINT_INIT(key_map);
got_error= 1;
new_file= -1;
@@ -3768,19 +3876,19 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
/*
Quick repair (not touching data file, rebuilding indexes):
{
- Read cache is (MI_CHECK *param)->read_cache using info->dfile.file.
+ Read cache is (HA_CHECK *param)->read_cache using info->dfile.file.
}
Non-quick repair (rebuilding data file and indexes):
{
Master thread:
- Read cache is (MI_CHECK *param)->read_cache using info->dfile.file.
- Write cache is (MI_INFO *info)->rec_cache using new_file.
+ Read cache is (HA_CHECK *param)->read_cache using info->dfile.file.
+ Write cache is (MARIA_INFO *info)->rec_cache using new_file.
Slave threads:
- Read cache is new_data_cache synced to master rec_cache.
+ Read cache is new_data_cache synced to master rec_cache.
The final assignment of the filedescriptor for rec_cache is done
after the cache creation.
@@ -3843,17 +3951,14 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
info->rec_cache.file=new_file;
}
- info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if (!(param->testflag & T_CREATE_MISSING_KEYS))
+ /* Optionally drop indexes and optionally modify the key_map. */
+ maria_drop_all_indexes(param, info, FALSE);
+ key_map= share->state.key_map;
+ if (param->testflag & T_CREATE_MISSING_KEYS)
{
- /* Clear the pointers to the given rows */
- for (i=0 ; i < share->base.keys ; i++)
- share->state.key_root[i]= HA_OFFSET_ERROR;
- share->state.key_del= HA_OFFSET_ERROR;
- info->state->key_file_length=share->base.keystart;
+ /* Invert the copied key_map to recreate all disabled indexes. */
+ key_map= ~key_map;
}
- else
- key_map= ~key_map; /* Create the missing keys */
param->read_cache.end_of_file= sort_info.filelength;
@@ -3892,6 +3997,10 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
sort_param[i].key=key;
sort_param[i].keyinfo=share->keyinfo+key;
sort_param[i].seg=sort_param[i].keyinfo->seg;
+ /*
+ Skip this index if it is marked disabled in the copied
+ (and possibly inverted) key_map.
+ */
if (! maria_is_key_active(key_map, key))
{
/* Remember old statistics for key */
@@ -5729,8 +5838,8 @@ void _ma_update_auto_increment_key(HA_CHECK *param, MARIA_HA *info,
We have to use an allocated buffer instead of info->rec_buff as
_ma_put_key_in_record() may use info->rec_buff
*/
- if (!(record= (uchar*) my_malloc((uint) share->base.pack_reclength,
- MYF(0))))
+ if (!(record= (uchar*) my_malloc((size_t) share->base.default_rec_buff_size,
+ MYF(0))))
{
_ma_check_print_error(param,"Not enough memory for extra record");
DBUG_VOID_RETURN;
diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c
index 23425152b33..129380736b8 100644
--- a/storage/maria/ma_delete.c
+++ b/storage/maria/ma_delete.c
@@ -81,7 +81,7 @@ int maria_delete(MARIA_HA *info,const uchar *record)
if (maria_is_key_active(share->state.key_map, i))
{
share->keyinfo[i].version++;
- if (share->keyinfo[i].flag & HA_FULLTEXT )
+ if (share->keyinfo[i].flag & HA_FULLTEXT)
{
if (_ma_ft_del(info, i, old_key, record, info->cur_row.lastpos))
goto err;
diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c
index d6c6e597fdb..daf170b4cbe 100644
--- a/storage/maria/ma_dynrec.c
+++ b/storage/maria/ma_dynrec.c
@@ -329,6 +329,29 @@ static my_bool write_dynamic_record(MARIA_HA *info, const uchar *record,
DBUG_ENTER("write_dynamic_record");
flag=0;
+
+ /*
+ Check if we have enough room for the new record.
+ First we do simplified check to make usual case faster.
+ Then we do more precise check for the space left.
+ Though it still is not absolutely precise, as
+ we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
+ less in the most of the cases.
+ */
+
+ if (unlikely(info->s->base.max_data_file_length -
+ info->state->data_file_length <
+ reclength + MARIA_MAX_DYN_BLOCK_HEADER))
+ {
+ if (info->s->base.max_data_file_length - info->state->data_file_length +
+ info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
+ reclength + MARIA_MAX_DYN_BLOCK_HEADER)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(1);
+ }
+ }
+
do
{
if (_ma_find_writepos(info,reclength,&filepos,&length))
@@ -771,6 +794,37 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
DBUG_ENTER("update_dynamic_record");
flag=block_info.second_read=0;
+ /*
+ Check if we have enough room for the record.
+ First we do simplified check to make usual case faster.
+ Then we do more precise check for the space left.
+ Though it still is not absolutely precise, as
+ we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
+ less in the most of the cases.
+ */
+
+ /*
+ compare with just the reclength as we're going
+ to get some space from the old replaced record
+ */
+ if (unlikely(info->s->base.max_data_file_length -
+ info->state->data_file_length < reclength))
+ {
+ /* If new record isn't longer, we can go on safely */
+ if (info->cur_row.total_length < reclength)
+ {
+ if (info->s->base.max_data_file_length - info->state->data_file_length +
+ info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
+ reclength - info->cur_row.total_length + MARIA_MAX_DYN_BLOCK_HEADER)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err;
+ }
+ }
+ }
+ /* Remember length for updated row if it's updated again */
+ info->cur_row.total_length= reclength;
+
while (reclength > 0)
{
if (filepos != info->s->state.dellink)
@@ -876,6 +930,7 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
if (block_info.next_filepos != HA_OFFSET_ERROR)
if (delete_dynamic_record(info,block_info.next_filepos,1))
goto err;
+
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -1420,6 +1475,7 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf,
}
if (block_of_record++ == 0) /* First block */
{
+ info->cur_row.total_length= block_info.rec_len;
if (block_info.rec_len > (uint) info->s->base.max_pack_length)
goto panic;
if (info->s->base.blobs)
@@ -1752,6 +1808,7 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
}
if (block_of_record == 0) /* First block */
{
+ info->cur_row.total_length= block_info.rec_len;
if (block_info.rec_len > (uint) share->base.max_pack_length)
goto panic;
info->cur_row.lastpos= filepos;
diff --git a/storage/maria/ma_ft_boolean_search.c b/storage/maria/ma_ft_boolean_search.c
index b9ed7b4cfd6..7db45dffb77 100644
--- a/storage/maria/ma_ft_boolean_search.c
+++ b/storage/maria/ma_ft_boolean_search.c
@@ -23,8 +23,14 @@
inside plus subtree. max_docid could be used by any word in plus
subtree, but it could be updated by plus-word only.
+ Fulltext "smarter index merge" optimization assumes that rows
+ it gets are ordered by doc_id. That is not the case when we
+ search for a word with truncation operator. It may return
+ rows in random order. Thus we may not use "smarter index merge"
+ optimization with "trunc-words".
+
The idea is: there is no need to search for docid smaller than
- biggest docid inside current plus subtree.
+ biggest docid inside current plus subtree or any upper plus subtree.
Examples:
+word1 word2
@@ -36,6 +42,13 @@
+(word1 -word2) +(+word3 word4)
share same max_docid
max_docid updated by word3
+ +word1 word2 (+word3 word4 (+word5 word6))
+ three subexpressions (including the top-level one),
+ every one has its own max_docid, updated by its plus word.
+ but for the search word6 uses
+ max(word1.max_docid, word3.max_docid, word5.max_docid),
+ while word4 uses, accordingly,
+ max(word1.max_docid, word3.max_docid).
*/
#define FT_CORE
@@ -104,14 +117,14 @@ typedef struct st_ftb_word
/* ^^^^^^^^^^^^^^^^^^ FTB_{EXPR,WORD} common section */
my_off_t docid[2]; /* for index search and for scan */
my_off_t key_root;
- my_off_t *max_docid;
+ FTB_EXPR *max_docid_expr;
MARIA_KEYDEF *keyinfo;
struct st_ftb_word *prev;
float weight;
uint ndepth;
uint len;
uchar off;
- uchar word[1];
+ uchar word[1];
} FTB_WORD;
typedef struct st_ft_info
@@ -208,13 +221,13 @@ static int ftb_query_add_word(MYSQL_FTPARSER_PARAM *param,
for (tmp_expr= ftb_param->ftbe; tmp_expr->up; tmp_expr= tmp_expr->up)
if (! (tmp_expr->flags & FTB_FLAG_YES))
break;
- ftbw->max_docid= &tmp_expr->max_docid;
+ ftbw->max_docid_expr= tmp_expr;
/* fall through */
case FT_TOKEN_STOPWORD:
if (! ftb_param->up_quot) break;
phrase_word= (FT_WORD *)alloc_root(&ftb_param->ftb->mem_root, sizeof(FT_WORD));
tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
- phrase_word->pos= (uchar *) word;
+ phrase_word->pos= (uchar*) word;
phrase_word->len= word_len;
tmp_element->data= (void *)phrase_word;
ftb_param->ftbe->phrase= list_add(ftb_param->ftbe->phrase, tmp_element);
@@ -240,7 +253,7 @@ static int ftb_query_add_word(MYSQL_FTPARSER_PARAM *param,
if (info->yesno > 0) ftbe->up->ythresh++;
ftb_param->ftbe= ftbe;
ftb_param->depth++;
- ftb_param->up_quot= (uchar *) info->quot;
+ ftb_param->up_quot= (uchar*) info->quot;
break;
case FT_TOKEN_RIGHT_PAREN:
if (ftb_param->ftbe->document)
@@ -275,12 +288,12 @@ static int ftb_parse_query_internal(MYSQL_FTPARSER_PARAM *param,
MYSQL_FTPARSER_BOOLEAN_INFO info;
CHARSET_INFO *cs= ftb_param->ftb->charset;
uchar **start= (uchar**) &query;
- char *end= query + len;
+ uchar *end= (uchar*) query + len;
FT_WORD w;
info.prev= ' ';
info.quot= 0;
- while (maria_ft_get_word(cs, start, (uchar *) end, &w, &info))
+ while (maria_ft_get_word(cs, start, end, &w, &info))
param->mysql_add_word(param, (char *) w.pos, w.len, &info);
return(0);
}
@@ -308,7 +321,7 @@ static int _ftb_parse_query(FTB *ftb, uchar *query, uint len,
param->mysql_add_word= ftb_query_add_word;
param->mysql_ftparam= (void *)&ftb_param;
param->cs= ftb->charset;
- param->doc= (char *) query;
+ param->doc= (char*) query;
param->length= len;
param->flags= 0;
param->mode= MYSQL_FTPARSER_FULL_BOOLEAN_INFO;
@@ -329,8 +342,9 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
int subkeys=1;
my_bool can_go_down;
MARIA_HA *info=ftb->info;
- uint off= 0, extra=HA_FT_WLEN+info->s->base.rec_reflength;
+ uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength;
uchar *lastkey_buf= ftbw->word+ftbw->off;
+ LINT_INIT(off);
if (ftbw->flags & FTB_FLAG_TRUNC)
lastkey_buf+=ftbw->len;
@@ -346,11 +360,17 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
else
{
uint sflag= SEARCH_BIGGER;
- if (ftbw->docid[0] < *ftbw->max_docid)
+ my_off_t max_docid=0;
+ FTB_EXPR *tmp;
+
+ for (tmp= ftbw->max_docid_expr; tmp; tmp= tmp->up)
+ set_if_bigger(max_docid, tmp->max_docid);
+
+ if (ftbw->docid[0] < max_docid)
{
sflag|= SEARCH_SAME;
- _ma_dpointer(info, (ftbw->word + ftbw->len + HA_FT_WLEN),
- *ftbw->max_docid);
+ _ma_dpointer(info, (uchar*) (ftbw->word + ftbw->len + HA_FT_WLEN),
+ max_docid);
}
r= _ma_search(info, ftbw->keyinfo, lastkey_buf,
USE_WHOLE_KEY, sflag, ftbw->key_root);
@@ -376,7 +396,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
if (!r && !ftbw->off)
{
r= ha_compare_text(ftb->charset,
- (uchar*) info->lastkey+1,
+ info->lastkey+1,
info->lastkey_length-extra-1,
(uchar*) ftbw->word+1,
ftbw->len-1,
@@ -429,8 +449,8 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
memcpy(lastkey_buf+off, info->lastkey, info->lastkey_length);
}
ftbw->docid[0]= info->cur_row.lastpos;
- if (ftbw->flags & FTB_FLAG_YES)
- *ftbw->max_docid= info->cur_row.lastpos;
+ if (ftbw->flags & FTB_FLAG_YES && !(ftbw->flags & FTB_FLAG_TRUNC))
+ ftbw->max_docid_expr->max_docid= info->cur_row.lastpos;
return 0;
}
@@ -473,7 +493,8 @@ static void _ftb_init_index_search(FT_INFO *ftb)
ftbe->up->flags|= FTB_FLAG_TRUNC, ftbe=ftbe->up)
{
if (ftbe->flags & FTB_FLAG_NO || /* 2 */
- ftbe->up->ythresh - ftbe->up->yweaks >1) /* 1 */
+ ftbe->up->ythresh - ftbe->up->yweaks >
+ (uint) test(ftbe->flags & FTB_FLAG_YES)) /* 1 */
{
FTB_EXPR *top_ftbe=ftbe->up;
ftbw->docid[0]=HA_OFFSET_ERROR;
@@ -503,8 +524,9 @@ static void _ftb_init_index_search(FT_INFO *ftb)
}
-FT_INFO * maria_ft_init_boolean_search(MARIA_HA *info, uint keynr, uchar *query,
- uint query_len, CHARSET_INFO *cs)
+FT_INFO * maria_ft_init_boolean_search(MARIA_HA *info, uint keynr,
+ uchar *query,
+ uint query_len, CHARSET_INFO *cs)
{
FTB *ftb;
FTB_EXPR *ftbe;
@@ -585,7 +607,7 @@ static int ftb_phrase_add_word(MYSQL_FTPARSER_PARAM *param,
MY_FTB_PHRASE_PARAM *phrase_param= param->mysql_ftparam;
FT_WORD *w= (FT_WORD *)phrase_param->document->data;
LIST *phrase, *document;
- w->pos= (uchar *) word;
+ w->pos= (uchar*) word;
w->len= word_len;
phrase_param->document= phrase_param->document->prev;
if (phrase_param->phrase_length > phrase_param->document_length)
@@ -600,8 +622,8 @@ static int ftb_phrase_add_word(MYSQL_FTPARSER_PARAM *param,
{
FT_WORD *phrase_word= (FT_WORD *)phrase->data;
FT_WORD *document_word= (FT_WORD *)document->data;
- if (my_strnncoll(phrase_param->cs,
- (uchar*) phrase_word->pos, phrase_word->len,
+ if (my_strnncoll(phrase_param->cs, (uchar*) phrase_word->pos,
+ phrase_word->len,
(uchar*) document_word->pos, document_word->len))
return 0;
}
@@ -615,11 +637,11 @@ static int ftb_check_phrase_internal(MYSQL_FTPARSER_PARAM *param,
{
FT_WORD word;
MY_FTB_PHRASE_PARAM *phrase_param= param->mysql_ftparam;
- const char *docend= document + len;
+ const uchar *docend= (uchar*) document + len;
while (maria_ft_simple_get_word(phrase_param->cs, (uchar**) &document,
- (const uchar *) docend, &word, FALSE))
+ docend, &word, FALSE))
{
- param->mysql_add_word(param, (char *) word.pos, word.len, 0);
+ param->mysql_add_word(param, (char*) word.pos, word.len, 0);
if (phrase_param->match)
break;
}
@@ -663,7 +685,7 @@ static int _ftb_check_phrase(FTB *ftb, const uchar *document, uint len,
param->mysql_add_word= ftb_phrase_add_word;
param->mysql_ftparam= (void *)&ftb_param;
param->cs= ftb->charset;
- param->doc= (char *)document;
+ param->doc= (char *) document;
param->length= len;
param->flags= 0;
param->mode= MYSQL_FTPARSER_WITH_STOPWORDS;
@@ -875,10 +897,10 @@ static int ftb_find_relevance_parse(MYSQL_FTPARSER_PARAM *param,
{
MY_FTB_FIND_PARAM *ftb_param= param->mysql_ftparam;
FT_INFO *ftb= ftb_param->ftb;
- char *end= doc + len;
+ uchar *end= (uchar*) doc + len;
FT_WORD w;
while (maria_ft_simple_get_word(ftb->charset, (uchar**) &doc,
- (const uchar *) end, &w, TRUE))
+ end, &w, TRUE))
param->mysql_add_word(param, (char *) w.pos, w.len, 0);
return(0);
}
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index a3fcac91d9a..bdcc10508d8 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -686,23 +686,24 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->page_type= PAGECACHE_PLAIN_PAGE;
share->now_transactional= share->base.born_transactional;
- if (share->data_file_type == DYNAMIC_RECORD)
+ /* Use pack_reclength as we don't want to modify base.pack_recklength */
+ if (share->state.header.org_data_file_type == DYNAMIC_RECORD)
{
- /* add bits used to pack data to pack_reclength for faster allocation */
+ /* add bits used to pack data to pack_reclength for faster allocation */
share->base.pack_reclength+= share->base.pack_bytes;
share->base.extra_rec_buff_size=
(ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER) + MARIA_SPLIT_LENGTH +
MARIA_REC_BUFF_OFFSET);
}
- share->base.default_rec_buff_size= (max(share->base.pack_reclength,
- share->base.max_key_length) +
- share->base.extra_rec_buff_size);
-
if (share->data_file_type == COMPRESSED_RECORD)
{
/* Need some extra bytes for decode_bytes */
- share->base.extra_rec_buff_size= 7;
+ share->base.extra_rec_buff_size+= 7;
}
+ share->base.default_rec_buff_size= max(share->base.pack_reclength +
+ share->base.extra_rec_buff_size,
+ share->base.max_key_length);
+
disk_pos_assert(disk_pos + share->base.fields *MARIA_COLUMNDEF_SIZE,
end_pos);
for (i= j= 0 ; i < share->base.fields ; i++)
diff --git a/storage/maria/ma_packrec.c b/storage/maria/ma_packrec.c
index 7d79a2fb982..bc0646975ee 100644
--- a/storage/maria/ma_packrec.c
+++ b/storage/maria/ma_packrec.c
@@ -200,7 +200,8 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
share->pack.header_length= uint4korr(header+4);
share->min_pack_length=(uint) uint4korr(header+8);
share->max_pack_length=(uint) uint4korr(header+12);
- set_if_bigger(share->base.pack_reclength,share->max_pack_length);
+ set_if_bigger(share->base.default_rec_buff_size,
+ share->max_pack_length + 7);
elements=uint4korr(header+16);
intervall_length=uint4korr(header+20);
trees=uint2korr(header+24);
@@ -605,7 +606,7 @@ static void fill_quick_table(uint16 *table, uint bits, uint max_bits,
*/
value|= (max_bits - bits) << 8 | IS_CHAR;
- for (end= table + (uint) (((uint) 1 << bits)); table < end; table++)
+ for (end= table + ((my_ptrdiff_t) 1 << bits); table < end; table++)
{
*table= (uint16) value;
}
diff --git a/storage/maria/ma_rnext_same.c b/storage/maria/ma_rnext_same.c
index 6782cf5b8cf..9f2ada701a7 100644
--- a/storage/maria/ma_rnext_same.c
+++ b/storage/maria/ma_rnext_same.c
@@ -66,8 +66,8 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
for (;;)
{
if ((error= _ma_search_next(info,keyinfo,info->lastkey,
- info->lastkey_length,SEARCH_BIGGER,
- info->s->state.key_root[inx])))
+ info->lastkey_length,SEARCH_BIGGER,
+ info->s->state.key_root[inx])))
break;
if (ha_key_cmp(keyinfo->seg, (uchar*) info->lastkey,
(uchar*) info->lastkey2,
diff --git a/storage/maria/ma_rt_index.c b/storage/maria/ma_rt_index.c
index f9246eb1b55..fea8b7c2d29 100644
--- a/storage/maria/ma_rt_index.c
+++ b/storage/maria/ma_rt_index.c
@@ -461,15 +461,16 @@ static uchar *maria_rtree_pick_key(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
uint nod_flag)
{
double increase;
- double best_incr= DBL_MAX;
+ double best_incr;
double perimeter;
double best_perimeter;
- uchar *best_key;
+ uchar *best_key= NULL;
uchar *k= rt_PAGE_FIRST_KEY(page_buf, nod_flag);
uchar *last= rt_PAGE_END(info, page_buf);
LINT_INIT(best_perimeter);
LINT_INIT(best_key);
+ LINT_INIT(best_incr);
for (; k < last; k= rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
{
@@ -514,22 +515,13 @@ static uchar *maria_rtree_pick_key(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
&area)) == -1.0)
return NULL;
/* The following should be safe, even if we compare doubles */
- if (increase < best_incr)
+ if (!best_key || increase < best_incr ||
+ ((increase == best_incr) && (area < best_area)))
{
best_key= k;
best_area= area;
best_incr= increase;
}
- else
- {
- /* The following should be safe, even if we compare doubles */
- if ((increase == best_incr) && (area < best_area))
- {
- best_key= k;
- best_area= area;
- best_incr= increase;
- }
- }
}
return best_key;
}
diff --git a/storage/maria/ma_rt_mbr.c b/storage/maria/ma_rt_mbr.c
index dbde616401a..91e62c56839 100644
--- a/storage/maria/ma_rt_mbr.c
+++ b/storage/maria/ma_rt_mbr.c
@@ -526,6 +526,9 @@ double maria_rtree_overlapping_area(HA_KEYSEG *keyseg, uchar* a, uchar* b,
/*
Calculates MBR_AREA(a+b) - MBR_AREA(a)
+ Note: when 'a' and 'b' objects are far from each other,
+ the area increase can be really big, so this function
+ can return 'inf' as a result.
*/
double maria_rtree_area_increase(HA_KEYSEG *keyseg, uchar *a, uchar *b,
diff --git a/storage/maria/ma_search.c b/storage/maria/ma_search.c
index 0ceafbf4d04..c50027616a9 100644
--- a/storage/maria/ma_search.c
+++ b/storage/maria/ma_search.c
@@ -1329,11 +1329,12 @@ int _ma_search_next(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
info->page_changed, info->keyread_buff_used));
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE,keyinfo->seg,key,key_length););
- /* Force full read if we are at last key or if we are not on a leaf
- and the key tree has changed since we used it last time
- Note that even if the key tree has changed since last read, we can use
- the last read data from the leaf if we haven't used the buffer for
- something else.
+ /*
+ Force full read if we are at last key or if we are not on a leaf
+ and the key tree has changed since we used it last time
+ Note that even if the key tree has changed since last read, we can use
+ the last read data from the leaf if we haven't used the buffer for
+ something else.
*/
if (((nextflag & SEARCH_BIGGER) && info->int_keypos >= info->int_maxpos) ||
diff --git a/storage/maria/ma_sort.c b/storage/maria/ma_sort.c
index 64f451982a9..cf5ab2d3723 100644
--- a/storage/maria/ma_sort.c
+++ b/storage/maria/ma_sort.c
@@ -569,9 +569,10 @@ int _ma_thr_write_keys(MARIA_SORT_PARAM *sort_param)
if (!mergebuf)
{
length=param->sort_buffer_length;
- while (length >= MIN_SORT_MEMORY && !mergebuf)
+ while (length >= MIN_SORT_MEMORY)
{
- mergebuf=my_malloc(length, MYF(0));
+ if ((mergebuf= my_malloc(length, MYF(0))))
+ break;
length=length*3/4;
}
if (!mergebuf)
@@ -909,6 +910,7 @@ merge_buffers(MARIA_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
count=error=0;
maxcount=keys/((uint) (Tb-Fb) +1);
+ DBUG_ASSERT(maxcount > 0);
LINT_INIT(to_start_filepos);
if (to_file)
to_start_filepos=my_b_tell(to_file);
diff --git a/storage/maria/ma_statrec.c b/storage/maria/ma_statrec.c
index 3e744e12045..43915ff5ec0 100644
--- a/storage/maria/ma_statrec.c
+++ b/storage/maria/ma_statrec.c
@@ -62,8 +62,8 @@ my_bool _ma_write_static_record(MARIA_HA *info, const uchar *record)
{
info->rec_cache.seek_not_done=1; /* We have done a seek */
if (info->s->file_write(info, record, info->s->base.reclength,
- info->state->data_file_length,
- info->s->write_flag))
+ info->state->data_file_length,
+ info->s->write_flag))
goto err;
if (info->s->base.pack_reclength != info->s->base.reclength)
{
diff --git a/storage/maria/ma_test2.c b/storage/maria/ma_test2.c
index dfb85df0a2d..43bd72e02d8 100644
--- a/storage/maria/ma_test2.c
+++ b/storage/maria/ma_test2.c
@@ -39,9 +39,9 @@ static void put_blob_in_record(uchar *blob_pos,char **blob_buffer,
static void copy_key(MARIA_HA *info, uint inx, uchar *record, uchar *key);
static int verbose= 0, testflag= 0, first_key= 0, async_io= 0, pagecacheing= 0;
-static int write_cacheing= 0, do_locking= 0, rec_pointer_size= 0, pack_fields= 1;
+static int write_cacheing= 0, do_locking= 0, rec_pointer_size= 0;
static int silent= 0, opt_quick_mode= 0, transactional= 0, skip_update= 0;
-static int die_in_middle_of_transaction= 0;
+static int die_in_middle_of_transaction= 0, pack_fields= 1;
static int pack_seg= HA_SPACE_PACK, pack_type= HA_PACK_KEY, remove_count= -1;
static int create_flag= 0, srand_arg= 0, checkpoint= 0;
static uint use_blob= 0, update_count= 0;
diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c
index e6f2e1aea5f..435fe22a3b0 100644
--- a/storage/maria/maria_chk.c
+++ b/storage/maria/maria_chk.c
@@ -1674,12 +1674,14 @@ static int maria_sort_records(HA_CHECK *param,
_ma_check_print_error(param,"Not enough memory for key block");
goto err;
}
- if (!(sort_param.record=(uchar*) my_malloc((uint) share->base.pack_reclength,
- MYF(0))))
+
+ if (!(sort_param.record=
+ (uchar*) my_malloc((uint) share->base.default_rec_buff_size, MYF(0))))
{
_ma_check_print_error(param,"Not enough memory for record");
goto err;
}
+
fn_format(param->temp_filename,name,"", MARIA_NAME_DEXT,2+4+32);
new_file= my_create(fn_format(param->temp_filename,
param->temp_filename,"",
diff --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c
index 1e6e8cd3ca1..6902f131f5b 100644
--- a/storage/maria/maria_pack.c
+++ b/storage/maria/maria_pack.c
@@ -3184,7 +3184,7 @@ static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count)
cur_sort_p= sort_counts;
while (cur_count_p < end_count_p)
*(cur_sort_p++)= cur_count_p++;
- (void) qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp);
+ (void) my_qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp);
/*
Assign faked counts.