summaryrefslogtreecommitdiff
path: root/storage/myisam/mi_check.c
diff options
context:
space:
mode:
authorjani@hynda.mysql.fi <>2007-11-14 16:32:03 +0200
committerjani@hynda.mysql.fi <>2007-11-14 16:32:03 +0200
commit88bcde76619a68696853aab4941ed8624797a696 (patch)
tree370a898ba665a98fe82dbd6ab8d039f5e4199e2e /storage/myisam/mi_check.c
parentee053112ee780a06490191e7e8fb3ca4082f33c7 (diff)
parent6223deb694946e5a2c3e46eaf4f2ce5624b5e78a (diff)
downloadmariadb-git-88bcde76619a68696853aab4941ed8624797a696.tar.gz
Merge hynda.mysql.fi:/home/my/mysql-5.1-main
into hynda.mysql.fi:/home/my/mysql-5.1-marvel
Diffstat (limited to 'storage/myisam/mi_check.c')
-rw-r--r--storage/myisam/mi_check.c224
1 files changed, 167 insertions, 57 deletions
diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index 7e9334d4cf6..29b702d51b0 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/myisam/mi_check.c
@@ -1378,6 +1378,139 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
} /* chk_data_link */
+/**
+ @brief Drop all indexes
+
+ @param[in] param check parameters
+ @param[in] info MI_INFO 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,
+ mi_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 mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force)
+{
+ MYISAM_SHARE *share= info->s;
+ MI_STATE_INFO *state= &share->state;
+ uint i;
+ int error;
+ DBUG_ENTER("mi_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],
+ mi_is_key_active(state->key_map, i)));
+ if ((state->key_root[i] != HA_OFFSET_ERROR) &&
+ !mi_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)
+ {
+ /*
+ All of the disabled indexes are empty. We can just recreate them.
+ Flush dirty blocks of this index file from key cache and remove
+ all blocks of this index file from key cache.
+ */
+ DBUG_PRINT("repair", ("all disabled are empty: create missing"));
+ error= flush_key_blocks(share->key_cache, share->kfile,
+ FLUSH_FORCE_WRITE);
+ goto end;
+ }
+ /*
+ We do now drop all indexes and declare them disabled. With the
+ T_CREATE_MISSING_KEYS flag, mi_repair*() will recreate all
+ disabled indexes and enable them.
+ */
+ mi_clear_all_keys_active(state->key_map);
+ DBUG_PRINT("repair", ("declared all indexes disabled"));
+ }
+
+ /* Remove all key blocks of this index file from key cache. */
+ if ((error= flush_key_blocks(share->key_cache, share->kfile,
+ FLUSH_IGNORE_CHANGED)))
+ goto end;
+
+ /* Clear index root block pointers. */
+ for (i= 0; i < share->base.keys; i++)
+ state->key_root[i]= HA_OFFSET_ERROR;
+
+ /* Clear the delete chains. */
+ for (i= 0; i < state->header.max_block_size_index; i++)
+ state->key_del[i]= HA_OFFSET_ERROR;
+
+ /* Reset index file length to end of index file header. */
+ info->state->key_file_length= share->base.keystart;
+
+ DBUG_PRINT("repair", ("dropped all indexes"));
+ /* error= 0; set by last (error= flush_key_bocks()). */
+
+ end:
+ DBUG_RETURN(error);
+}
+
+
/* Recover old table by reading each record and writing all keys */
/* Save new datafile-name in temp_filename */
@@ -1385,7 +1518,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
char * name, int rep_quick)
{
int error,got_error;
- uint i;
ha_rows start_records,new_header_length;
my_off_t del;
File new_file;
@@ -1489,25 +1621,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- /*
- Clear all keys. Note that all key blocks allocated until now remain
- "dead" parts of the key file. (Bug #4692)
- */
- for (i=0 ; i < info->s->base.keys ; i++)
- share->state.key_root[i]= HA_OFFSET_ERROR;
-
- /* Drop the delete chain. */
- for (i=0 ; i < share->state.header.max_block_size_index ; i++)
- share->state.key_del[i]= HA_OFFSET_ERROR;
-
- /*
- If requested, activate (enable) all keys in key_map. In this case,
- all indexes will be (re-)built.
- */
+ /* This function always recreates all enabled indexes. */
if (param->testflag & T_CREATE_MISSING_KEYS)
mi_set_all_keys_active(share->state.key_map, share->base.keys);
-
- info->state->key_file_length=share->base.keystart;
+ mi_drop_all_indexes(param, info, TRUE);
lock_memory(param); /* Everything is alloced */
@@ -2108,8 +2225,9 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
ulong *rec_per_key_part;
char llbuff[22];
SORT_INFO sort_info;
- ulonglong key_map=share->state.key_map;
+ ulonglong key_map;
DBUG_ENTER("mi_repair_by_sort");
+ LINT_INIT(key_map);
start_records=info->state->records;
got_error=1;
@@ -2182,25 +2300,14 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
}
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if (!(param->testflag & T_CREATE_MISSING_KEYS))
- {
- /*
- Flush key cache for this file if we are calling this outside
- myisamchk
- */
- flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED);
- /* Clear the pointers to the given rows */
- for (i=0 ; i < share->base.keys ; i++)
- share->state.key_root[i]= HA_OFFSET_ERROR;
- for (i=0 ; i < share->state.header.max_block_size_index ; i++)
- share->state.key_del[i]= HA_OFFSET_ERROR;
- info->state->key_file_length=share->base.keystart;
- }
- else
+
+ /* Optionally drop indexes and optionally modify the key_map. */
+ mi_drop_all_indexes(param, info, FALSE);
+ key_map= share->state.key_map;
+ if (param->testflag & T_CREATE_MISSING_KEYS)
{
- if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_FORCE_WRITE))
- goto err;
- key_map= ~key_map; /* Create the missing keys */
+ /* Invert the copied key_map to recreate all disabled indexes. */
+ key_map= ~key_map;
}
sort_info.info=info;
@@ -2244,6 +2351,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
sort_param.read_cache=param->read_cache;
sort_param.keyinfo=share->keyinfo+sort_param.key;
sort_param.seg=sort_param.keyinfo->seg;
+ /*
+ Skip this index if it is marked disabled in the copied
+ (and possibly inverted) key_map.
+ */
if (! mi_is_key_active(key_map, sort_param.key))
{
/* Remember old statistics for key */
@@ -2251,6 +2362,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
(char*) (share->state.rec_per_key_part +
(uint) (rec_per_key_part - param->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;
}
@@ -2331,8 +2444,11 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
if (param->testflag & T_STATISTICS)
update_key_parts(sort_param.keyinfo, rec_per_key_part, sort_param.unique,
param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
- sort_param.notnull: NULL,(ulonglong) info->state->records);
+ sort_param.notnull: NULL,
+ (ulonglong) info->state->records);
+ /* Enable this index in the permanent (not the copied) key_map. */
mi_set_key_active(share->state.key_map, sort_param.key);
+ DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key));
if (sort_param.fix_datafile)
{
@@ -2533,9 +2649,10 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
IO_CACHE new_data_cache; /* For non-quick repair. */
IO_CACHE_SHARE io_share;
SORT_INFO sort_info;
- ulonglong key_map=share->state.key_map;
+ ulonglong key_map;
pthread_attr_t thr_attr;
DBUG_ENTER("mi_repair_parallel");
+ LINT_INIT(key_map);
start_records=info->state->records;
got_error=1;
@@ -2637,25 +2754,14 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
}
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if (!(param->testflag & T_CREATE_MISSING_KEYS))
- {
- /*
- Flush key cache for this file if we are calling this outside
- myisamchk
- */
- flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED);
- /* Clear the pointers to the given rows */
- for (i=0 ; i < share->base.keys ; i++)
- share->state.key_root[i]= HA_OFFSET_ERROR;
- for (i=0 ; i < share->state.header.max_block_size_index ; i++)
- share->state.key_del[i]= HA_OFFSET_ERROR;
- info->state->key_file_length=share->base.keystart;
- }
- else
+
+ /* Optionally drop indexes and optionally modify the key_map. */
+ mi_drop_all_indexes(param, info, FALSE);
+ key_map= share->state.key_map;
+ if (param->testflag & T_CREATE_MISSING_KEYS)
{
- if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_FORCE_WRITE))
- goto err;
- key_map= ~key_map; /* Create the missing keys */
+ /* Invert the copied key_map to recreate all disabled indexes. */
+ key_map= ~key_map;
}
sort_info.info=info;
@@ -2711,6 +2817,10 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *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 (! mi_is_key_active(key_map, key))
{
/* Remember old statistics for key */