summaryrefslogtreecommitdiff
path: root/storage/maria/ma_check.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/maria/ma_check.c')
-rw-r--r--storage/maria/ma_check.c209
1 files changed, 159 insertions, 50 deletions
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;