Commit 828bff91 authored by monty@donna.mysql.com's avatar monty@donna.mysql.com

Fixes for automatic recover of MyISAM tables

parent 2620ca4c
...@@ -9036,9 +9036,9 @@ priority in one thread. ...@@ -9036,9 +9036,9 @@ priority in one thread.
@item --memlock @item --memlock
Lock the @code{mysqld} process in memory. This works only if your system Lock the @code{mysqld} process in memory. This works only if your system
supports the @code{mlockall()} system call. This may help if you have supports the @code{mlockall()} system call. This may help if you have
a problem where the opearting system is causing @code{mysqld} to swap on disk. a problem where the operating system is causing @code{mysqld} to swap on disk.
@item --myisam-recover [=option[,option...]]] where option is one of DEFAULT, BACKUP or FORCE. @item --myisam-recover [=option[,option...]]] where option is one of DEFAULT, BACKUP, FORCE or QUICK.
If this option is used, @code{mysqld} will on open check if the table is If this option is used, @code{mysqld} will on open check if the table is
marked as crashed or if if the table wasn't closed properly marked as crashed or if if the table wasn't closed properly
(The last option only works if you are running with @code{--skip-locking}). (The last option only works if you are running with @code{--skip-locking}).
...@@ -9051,10 +9051,15 @@ The following options affects how the repair works. ...@@ -9051,10 +9051,15 @@ The following options affects how the repair works.
@item DEFAULT @tab The same as not giving any option to @code{--myisam-recover}. @item DEFAULT @tab The same as not giving any option to @code{--myisam-recover}.
@item BACKUP @tab If the data table was changed during recover, save a backup of the @file{table_name.MYD} data file as @file{table_name-datetime.BAK}. @item BACKUP @tab If the data table was changed during recover, save a backup of the @file{table_name.MYD} data file as @file{table_name-datetime.BAK}.
@item FORCE @tab Run recover even if we will loose more than one row from the .MYD file. @item FORCE @tab Run recover even if we will loose more than one row from the .MYD file.
@item QUICK @tab Don't check the rows in the table if there isn't any delete blocks.
@end multitable @end multitable
Before a table is automaticly repaired, mysqld will add a note about this Before a table is automaticly repaired, mysqld will add a note about
in the error log. this in the error log. If you want to be able to recover from most
things without user intervention, you should use the options
@code{BACKUP,FORCE}. This will force a repair of a table even if some rows
would be deleted, but it will keep the old data file as a backup so that
you can later examine what happened.
@item --pid-file=path @item --pid-file=path
Path to pid file used by @code{safe_mysqld}. Path to pid file used by @code{safe_mysqld}.
...@@ -21266,7 +21271,7 @@ of both worlds. ...@@ -21266,7 +21271,7 @@ of both worlds.
@menu @menu
* MyISAM:: MyISAM tables * MyISAM:: MyISAM tables
* MERGE:: * MERGE:: MERGE tables
* ISAM:: ISAM tables * ISAM:: ISAM tables
* HEAP:: HEAP tables * HEAP:: HEAP tables
* BDB:: BDB or Berkeley_db tables * BDB:: BDB or Berkeley_db tables
...@@ -21378,11 +21383,37 @@ The following options to @code{mysqld} can be used to change the behavior of ...@@ -21378,11 +21383,37 @@ The following options to @code{mysqld} can be used to change the behavior of
@multitable @columnfractions .40 .60 @multitable @columnfractions .40 .60
@item @strong{Option} @tab @strong{Meaning} @item @strong{Option} @tab @strong{Meaning}
@item @code{--myisam-recover} @tab Automatic recover of crashed tables. @item @code{--myisam-recover=#} @tab Automatic recover of crashed tables.
@item @code{-O myisam_sort_buffer_size=#} @tab Buffer used when recovering tables. @item @code{-O myisam_sort_buffer_size=#} @tab Buffer used when recovering tables.
@item @code{--delay-key-write-for-all-tables} @tab Don't flush key buffers between writes for any MyISAM table @item @code{--delay-key-write-for-all-tables} @tab Don't flush key buffers between writes for any MyISAM table
@end multitable @end multitable
The automatic recovery is activated if you start mysqld with
@code{--myisam-recover=#}. @xref{Command-line options}.
On open, the table is checked if it's marked as crashed or if the open
count variable for the table is not 0 and you are running with
@code{--skip-locking}. If either of the above is true the following happens.
@itemize @bullet
@item
The table is checked for errors.
@item
If we found an error, try to do a fast repair (with sorting and without
recreating the data file) of the table.
@item
If the repair fails because of an error in the data file (for example a
duplicate key error), we try again, but this time we recreate the data file.
@item
If the repair fails, retry once more with the old repair option method
(write row by row without sorting) which should be able to repair any
type of error with little disk requirements..
@end itemize
Note that if you run automatic recover with the @code{BACKUP} option,
you should have a cron script that automaticly moves file with names
like @file{tablename-datetime.BAK} from the database directories to a
backup media.
@xref{Command-line options}. @xref{Command-line options}.
@menu @menu
...@@ -1186,7 +1186,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, ...@@ -1186,7 +1186,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
sort_info->dupp++; sort_info->dupp++;
if (rep_quick == 1) if (rep_quick == 1)
{ {
param->error_printed=1; param->error_printed=param->retry_without_quick=1;
goto err; goto err;
} }
continue; continue;
...@@ -1218,6 +1218,16 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, ...@@ -1218,6 +1218,16 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
param->retry_repair=param->retry_without_quick=1; param->retry_repair=param->retry_without_quick=1;
goto err; goto err;
} }
if (param->testflag & T_SAFE_REPAIR)
{
/* Don't repair if we loosed more than one row */
if (info->state->records+1 < start_records)
{
info->state->records=start_records;
got_error=1;
goto err;
}
}
if (!rep_quick) if (!rep_quick)
{ {
...@@ -1226,7 +1236,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, ...@@ -1226,7 +1236,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
info->state->data_file_length=sort_info->filepos; info->state->data_file_length=sort_info->filepos;
/* Only whole records */ /* Only whole records */
share->state.split=info->state->records+info->state->del; share->state.split=info->state->records+info->state->del;
param->out_flag|=O_NEW_DATA; /* Data in new file */
share->state.version=(ulong) time((time_t*) 0); /* Force reopen */ share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
} }
else else
...@@ -1248,6 +1257,21 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, ...@@ -1248,6 +1257,21 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
memcpy( &share->state.state, info->state, sizeof(*info->state)); memcpy( &share->state.state, info->state, sizeof(*info->state));
err: err:
if (!got_error)
{
/* Replace the actual file with the temporary file */
if (new_file >= 0)
{
my_close(new_file,MYF(0));
info->dfile=new_file= -1;
if (change_to_newfile(share->filename,MI_NAME_DEXT,
DATA_TMP_EXT, share->base.raid_chunks,
(param->testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
mi_open_datafile(info,share))
got_error=1;
}
}
if (got_error) if (got_error)
{ {
if (! param->error_printed) if (! param->error_printed)
...@@ -1275,7 +1299,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, ...@@ -1275,7 +1299,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
share->pack.header_length=0; share->pack.header_length=0;
share->data_file_type=sort_info->new_data_file_type; share->data_file_type=sort_info->new_data_file_type;
} }
share->state.changed|=STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES; share->state.changed|= (STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES |
STATE_NOT_ANALYZED);
DBUG_RETURN(got_error); DBUG_RETURN(got_error);
} }
...@@ -1454,14 +1479,17 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) ...@@ -1454,14 +1479,17 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
flush_key_blocks(info->s->kfile, FLUSH_IGNORE_CHANGED); flush_key_blocks(info->s->kfile, FLUSH_IGNORE_CHANGED);
/* Put same locks as old file */ /* Put same locks as old file */
if (lock_file(param,new_file,0L,F_WRLCK,"tempfile",param->temp_filename))
goto err;
info->s->state.version=(ulong) time((time_t*) 0); info->s->state.version=(ulong) time((time_t*) 0);
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
VOID(my_close(info->s->kfile,MYF(MY_WME))); VOID(my_close(info->s->kfile,MYF(MY_WME)));
param->out_flag|=O_NEW_INDEX; /* Data in new file */ info->s->kfile = -1;
VOID(my_close(new_file,MYF(MY_WME)));
if (change_to_newfile(info->s->filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
MYF(0)) ||
mi_open_keyfile(info->s))
goto err2;
_mi_readinfo(info,F_WRLCK,0);
info->s->kfile=new_file;
info->state->key_file_length=param->new_file_pos; info->state->key_file_length=param->new_file_pos;
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
for (key=0 ; key < info->s->base.keys ; key++) for (key=0 ; key < info->s->base.keys ; key++)
...@@ -1474,6 +1502,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) ...@@ -1474,6 +1502,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
err: err:
VOID(my_close(new_file,MYF(MY_WME))); VOID(my_close(new_file,MYF(MY_WME)));
err2:
VOID(my_delete(param->temp_filename,MYF(MY_WME))); VOID(my_delete(param->temp_filename,MYF(MY_WME)));
DBUG_RETURN(-1); DBUG_RETURN(-1);
} /* sort_index */ } /* sort_index */
...@@ -1843,7 +1872,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1843,7 +1872,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
/* Only whole records */ /* Only whole records */
share->state.split=info->state->records+info->state->del; share->state.split=info->state->records+info->state->del;
share->state.version=(ulong) time((time_t*) 0); share->state.version=(ulong) time((time_t*) 0);
param->out_flag|=O_NEW_DATA; /* Data in new file */
my_close(info->dfile,MYF(0)); my_close(info->dfile,MYF(0));
info->dfile=new_file; info->dfile=new_file;
share->data_file_type=sort_info->new_data_file_type; share->data_file_type=sort_info->new_data_file_type;
...@@ -1910,18 +1938,34 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1910,18 +1938,34 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
memcpy( &share->state.state, info->state, sizeof(*info->state)); memcpy( &share->state.state, info->state, sizeof(*info->state));
err: err:
got_error|= flush_blocks(param,share->kfile);
VOID(end_io_cache(&info->rec_cache));
if (!got_error)
{
/* Replace the actual file with the temporary file */
if (new_file >= 0)
{
my_close(new_file,MYF(0));
info->dfile=new_file= -1;
if (change_to_newfile(share->filename,MI_NAME_DEXT,
DATA_TMP_EXT, share->base.raid_chunks,
(param->testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
mi_open_datafile(info,share))
got_error=1;
}
}
if (got_error) if (got_error)
{ {
if (! param->error_printed) if (! param->error_printed)
mi_check_print_error(param,"%d when fixing table",my_errno); mi_check_print_error(param,"%d when fixing table",my_errno);
if (new_file >= 0) if (new_file >= 0)
{ {
VOID(end_io_cache(&info->rec_cache));
VOID(my_close(new_file,MYF(0))); VOID(my_close(new_file,MYF(0)));
VOID(my_raid_delete(param->temp_filename,info->s->base.raid_chunks, VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks,
MYF(MY_WME))); MYF(MY_WME)));
if (info->dfile == new_file) if (info->dfile == new_file)
info->dfile=0; info->dfile= -1;
} }
mi_mark_crashed_on_repair(info); mi_mark_crashed_on_repair(info);
} }
...@@ -1933,7 +1977,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1933,7 +1977,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
my_free(sort_info->record,MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info->record,MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_info->buff,MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info->buff,MYF(MY_ALLOW_ZERO_PTR));
VOID(end_io_cache(&param->read_cache)); VOID(end_io_cache(&param->read_cache));
VOID(end_io_cache(&info->rec_cache));
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
if (!got_error && (param->testflag & T_UNPACK)) if (!got_error && (param->testflag & T_UNPACK))
{ {
...@@ -2441,6 +2484,7 @@ static int sort_key_write(SORT_INFO *sort_info, const void *a) ...@@ -2441,6 +2484,7 @@ static int sort_key_write(SORT_INFO *sort_info, const void *a)
sort_info->key_block-> sort_info->key_block->
lastkey), lastkey),
llbuff2)); llbuff2));
param->error_printed=param->retry_without_quick=1;
if (sort_info->param->testflag & T_VERBOSE) if (sort_info->param->testflag & T_VERBOSE)
_mi_print_key(stdout,sort_info->keyseg,(uchar*) a, USE_WHOLE_KEY); _mi_print_key(stdout,sort_info->keyseg,(uchar*) a, USE_WHOLE_KEY);
return (sort_delete_record(param)); return (sort_delete_record(param));
...@@ -2475,7 +2519,7 @@ static int sort_insert_key(MI_CHECK *param, ...@@ -2475,7 +2519,7 @@ static int sort_insert_key(MI_CHECK *param,
my_off_t prev_block) my_off_t prev_block)
{ {
uint a_length,t_length,nod_flag; uint a_length,t_length,nod_flag;
my_off_t filepos; my_off_t filepos,key_file_length;
uchar *anc_buff,*lastkey; uchar *anc_buff,*lastkey;
MI_KEY_PARAM s_temp; MI_KEY_PARAM s_temp;
MI_INFO *info; MI_INFO *info;
...@@ -2526,11 +2570,20 @@ static int sort_insert_key(MI_CHECK *param, ...@@ -2526,11 +2570,20 @@ static int sort_insert_key(MI_CHECK *param,
mi_putint(anc_buff,key_block->last_length,nod_flag); mi_putint(anc_buff,key_block->last_length,nod_flag);
bzero((byte*) anc_buff+key_block->last_length, bzero((byte*) anc_buff+key_block->last_length,
sort_info->keyinfo->block_length- key_block->last_length); sort_info->keyinfo->block_length- key_block->last_length);
key_file_length=info->state->key_file_length;
if ((filepos=_mi_new(info,sort_info->keyinfo)) == HA_OFFSET_ERROR) if ((filepos=_mi_new(info,sort_info->keyinfo)) == HA_OFFSET_ERROR)
return 1; DBUG_RETURN(1);
if (my_pwrite(info->s->kfile,(byte*) anc_buff,
(uint) sort_info->keyinfo->block_length,filepos, /* If we read the page from the key cache, we have to write it back to it */
param->myf_rw)) if (key_file_length == info->state->key_file_length)
{
if (_mi_write_keypage(info, sort_info->keyinfo, filepos,
anc_buff))
DBUG_RETURN(1);
}
else if (my_pwrite(info->s->kfile,(byte*) anc_buff,
(uint) sort_info->keyinfo->block_length,filepos,
param->myf_rw))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_DUMP("buff",(byte*) anc_buff,mi_getint(anc_buff)); DBUG_DUMP("buff",(byte*) anc_buff,mi_getint(anc_buff));
...@@ -2608,7 +2661,7 @@ static int sort_delete_record(MI_CHECK *param) ...@@ -2608,7 +2661,7 @@ static int sort_delete_record(MI_CHECK *param)
static int flush_pending_blocks(MI_CHECK *param) static int flush_pending_blocks(MI_CHECK *param)
{ {
uint nod_flag,length; uint nod_flag,length;
my_off_t filepos; my_off_t filepos,key_file_length;
MI_INFO *info; MI_INFO *info;
SORT_KEY_BLOCKS *key_block; SORT_KEY_BLOCKS *key_block;
SORT_INFO *sort_info= &param->sort_info; SORT_INFO *sort_info= &param->sort_info;
...@@ -2623,18 +2676,27 @@ static int flush_pending_blocks(MI_CHECK *param) ...@@ -2623,18 +2676,27 @@ static int flush_pending_blocks(MI_CHECK *param)
length=mi_getint(key_block->buff); length=mi_getint(key_block->buff);
if (nod_flag) if (nod_flag)
_mi_kpointer(info,key_block->end_pos,filepos); _mi_kpointer(info,key_block->end_pos,filepos);
if ((filepos=_mi_new(info,sort_info->keyinfo)) == HA_OFFSET_ERROR) key_file_length=info->state->key_file_length;
DBUG_RETURN(1);
bzero((byte*) key_block->buff+length, bzero((byte*) key_block->buff+length,
sort_info->keyinfo->block_length-length); sort_info->keyinfo->block_length-length);
if (my_pwrite(info->s->kfile,(byte*) key_block->buff, if ((filepos=_mi_new(info,sort_info->keyinfo)) == HA_OFFSET_ERROR)
(uint) sort_info->keyinfo->block_length,filepos, DBUG_RETURN(1);
param->myf_rw))
/* If we read the page from the key cache, we have to write it back */
if (key_file_length == info->state->key_file_length)
{
if (_mi_write_keypage(info, sort_info->keyinfo, filepos,
key_block->buff))
DBUG_RETURN(1);
}
else if (my_pwrite(info->s->kfile,(byte*) key_block->buff,
(uint) sort_info->keyinfo->block_length,filepos,
param->myf_rw))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_DUMP("buff",(byte*) key_block->buff,length); DBUG_DUMP("buff",(byte*) key_block->buff,length);
nod_flag=1; nod_flag=1;
} }
info->s->state.key_root[sort_info->key]=filepos; /* Last is root for tree */ info->s->state.key_root[sort_info->key]=filepos; /* Last is root for tree */
DBUG_RETURN(0); DBUG_RETURN(0);
} /* flush_pending_blocks */ } /* flush_pending_blocks */
......
...@@ -99,6 +99,7 @@ int _mi_dispose(register MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos) ...@@ -99,6 +99,7 @@ int _mi_dispose(register MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos)
my_off_t old_link; my_off_t old_link;
char buff[8]; char buff[8];
DBUG_ENTER("_mi_dispose"); DBUG_ENTER("_mi_dispose");
DBUG_PRINT("enter",("pos: %ld", (long) pos));
old_link=info->s->state.key_del[keyinfo->block_size]; old_link=info->s->state.key_del[keyinfo->block_size];
info->s->state.key_del[keyinfo->block_size]=pos; info->s->state.key_del[keyinfo->block_size]=pos;
...@@ -141,6 +142,6 @@ my_off_t _mi_new(register MI_INFO *info, MI_KEYDEF *keyinfo) ...@@ -141,6 +142,6 @@ my_off_t _mi_new(register MI_INFO *info, MI_KEYDEF *keyinfo)
info->s->state.key_del[keyinfo->block_size]=mi_sizekorr(buff); info->s->state.key_del[keyinfo->block_size]=mi_sizekorr(buff);
} }
info->s->state.changed|= STATE_NOT_SORTED_PAGES; info->s->state.changed|= STATE_NOT_SORTED_PAGES;
DBUG_PRINT("exit",("Pos: %d",pos)); DBUG_PRINT("exit",("Pos: %ld",(long) pos));
DBUG_RETURN(pos); DBUG_RETURN(pos);
} /* _mi_new */ } /* _mi_new */
...@@ -481,6 +481,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) ...@@ -481,6 +481,7 @@ static int myisamchk(MI_CHECK *param, my_string filename)
File datafile; File datafile;
char fixed_name[FN_REFLEN]; char fixed_name[FN_REFLEN];
char llbuff[22],llbuff2[22]; char llbuff[22],llbuff2[22];
my_bool state_updated=0;
MYISAM_SHARE *share; MYISAM_SHARE *share;
DBUG_ENTER("myisamchk"); DBUG_ENTER("myisamchk");
...@@ -665,12 +666,20 @@ static int myisamchk(MI_CHECK *param, my_string filename) ...@@ -665,12 +666,20 @@ static int myisamchk(MI_CHECK *param, my_string filename)
(share->state.key_map || (share->state.key_map ||
(rep_quick && !param->keys_in_use && !recreate)) && (rep_quick && !param->keys_in_use && !recreate)) &&
mi_test_if_sort_rep(info, info->state->records, 1)) mi_test_if_sort_rep(info, info->state->records, 1))
{
error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick); error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick);
state_updated=1;
}
else if (param->testflag & (T_REP | T_REP_BY_SORT)) else if (param->testflag & (T_REP | T_REP_BY_SORT))
error=mi_repair(&check_param, info,fixed_name,rep_quick); error=mi_repair(&check_param, info,fixed_name,rep_quick);
} }
if (!error && param->testflag & T_SORT_RECORDS) if (!error && param->testflag & T_SORT_RECORDS)
{ {
/*
The data file is nowadays reopened in the repair code so we should
soon remove the following reopen-code
*/
#ifndef TO_BE_REMOVED
if (param->out_flag & O_NEW_DATA) if (param->out_flag & O_NEW_DATA)
{ /* Change temp file to org file */ { /* Change temp file to org file */
VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */ VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
...@@ -682,6 +691,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) ...@@ -682,6 +691,7 @@ static int myisamchk(MI_CHECK *param, my_string filename)
param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */ param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
param->read_cache.file=info->dfile; param->read_cache.file=info->dfile;
} }
#endif
if (! error) if (! error)
{ {
uint key; uint key;
...@@ -737,7 +747,11 @@ static int myisamchk(MI_CHECK *param, my_string filename) ...@@ -737,7 +747,11 @@ static int myisamchk(MI_CHECK *param, my_string filename)
{ {
error|=chk_key(param, info); error|=chk_key(param, info);
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC))) if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
error=update_state_info(param, info, UPDATE_STAT); error=update_state_info(param, info,
((param->testflag & T_STATISTICS) ?
UPDATE_STAT : 0) |
((param->testflag & T_AUTO_INC) ?
UPDATE_AUTO_INC : 0));
} }
if ((!rep_quick && !error) || if ((!rep_quick && !error) ||
!(param->testflag & (T_FAST | T_FORCE_CREATE))) !(param->testflag & (T_FAST | T_FORCE_CREATE)))
...@@ -788,7 +802,8 @@ static int myisamchk(MI_CHECK *param, my_string filename) ...@@ -788,7 +802,8 @@ static int myisamchk(MI_CHECK *param, my_string filename)
error|=update_state_info(param, info, error|=update_state_info(param, info,
UPDATE_OPEN_COUNT | UPDATE_OPEN_COUNT |
(((param->testflag & (T_REP | T_REP_BY_SORT)) ? (((param->testflag & (T_REP | T_REP_BY_SORT)) ?
UPDATE_TIME | UPDATE_STAT : 0) | UPDATE_TIME : 0) |
(state_updated ? UPDATE_STAT : 0) |
((param->testflag & T_SORT_RECORDS) ? ((param->testflag & T_SORT_RECORDS) ?
UPDATE_SORT : 0))); UPDATE_SORT : 0)));
VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename)); VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename));
...@@ -1244,7 +1259,7 @@ static int mi_sort_records(MI_CHECK *param, ...@@ -1244,7 +1259,7 @@ static int mi_sort_records(MI_CHECK *param,
{ {
VOID(end_io_cache(&info->rec_cache)); VOID(end_io_cache(&info->rec_cache));
(void) my_close(new_file,MYF(MY_WME)); (void) my_close(new_file,MYF(MY_WME));
(void) my_raid_delete(param->temp_filename, share->base.raid_chunksize, (void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
MYF(MY_WME)); MYF(MY_WME));
} }
if (temp_buff) if (temp_buff)
......
...@@ -83,7 +83,7 @@ int pthread_create(pthread_t *thread_id, pthread_attr_t *attr, ...@@ -83,7 +83,7 @@ int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
attr->dwStackSize ? attr->dwStackSize : attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map); 65535, (void*) map);
#else #else
hThread=(HANDLE)_beginthread(pthread_start, hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
attr->dwStackSize ? attr->dwStackSize : attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map); 65535, (void*) map);
#endif #endif
......
...@@ -411,6 +411,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -411,6 +411,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
int error; int error;
if (!file) return HA_ADMIN_INTERNAL_ERROR; if (!file) return HA_ADMIN_INTERNAL_ERROR;
MI_CHECK param; MI_CHECK param;
ha_rows start_records;
myisamchk_init(&param); myisamchk_init(&param);
param.thd = thd; param.thd = thd;
...@@ -420,8 +421,10 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -420,8 +421,10 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
if (check_opt->quick) if (check_opt->quick)
param.opt_rep_quick++; param.opt_rep_quick++;
param.sort_buffer_length= check_opt->sort_buffer_size; param.sort_buffer_length= check_opt->sort_buffer_size;
while ((error=repair(thd,param,0))) start_records=file->state->records;
while ((error=repair(thd,param,0)) && param.retry_repair)
{ {
param.retry_repair=0;
if (param.retry_without_quick && param.opt_rep_quick) if (param.retry_without_quick && param.opt_rep_quick)
{ {
param.opt_rep_quick=0; param.opt_rep_quick=0;
...@@ -438,6 +441,14 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -438,6 +441,14 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
} }
break; break;
} }
if (!error && start_records != file->state->records)
{
char llbuff[22],llbuff2[22];
sql_print_error("Warning: Found %s of %s rows from %s",
llstr(file->state->records, llbuff),
llstr(start_records, llbuff2),
table->path);
}
return error; return error;
} }
...@@ -461,7 +472,7 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -461,7 +472,7 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
{ {
int error=0; int error=0;
bool optimize_done= !optimize; bool optimize_done= !optimize, statistics_done=0;
char fixed_name[FN_REFLEN]; char fixed_name[FN_REFLEN];
const char *old_proc_info=thd->proc_info; const char *old_proc_info=thd->proc_info;
MYISAM_SHARE* share = file->s; MYISAM_SHARE* share = file->s;
...@@ -487,11 +498,13 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -487,11 +498,13 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
{ {
param.testflag|= T_STATISTICS; // We get this for free param.testflag|= T_STATISTICS; // We get this for free
thd->proc_info="Repair by sorting"; thd->proc_info="Repair by sorting";
statistics_done=1;
error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick); error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick);
} }
else else
{ {
thd->proc_info="Repair with keycache"; thd->proc_info="Repair with keycache";
param.testflag &= ~T_REP_BY_SORT;
error= mi_repair(&param, file, fixed_name, param.opt_rep_quick); error= mi_repair(&param, file, fixed_name, param.opt_rep_quick);
} }
} }
...@@ -504,7 +517,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -504,7 +517,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
thd->proc_info="Sorting index"; thd->proc_info="Sorting index";
error=mi_sort_index(&param,file,fixed_name); error=mi_sort_index(&param,file,fixed_name);
} }
if ((param.testflag & T_STATISTICS) && if (!statistics_done && (param.testflag & T_STATISTICS) &&
(share->state.changed & STATE_NOT_ANALYZED)) (share->state.changed & STATE_NOT_ANALYZED))
{ {
optimize_done=1; optimize_done=1;
...@@ -525,7 +538,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -525,7 +538,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
if (file->s->base.auto_key) if (file->s->base.auto_key)
update_auto_increment_key(&param, file, 1); update_auto_increment_key(&param, file, 1);
error = update_state_info(&param, file, error = update_state_info(&param, file,
UPDATE_TIME | UPDATE_TIME | UPDATE_OPEN_COUNT |
(param.testflag & T_STATISTICS ? (param.testflag & T_STATISTICS ?
UPDATE_STAT : 0)); UPDATE_STAT : 0));
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
...@@ -536,48 +549,6 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -536,48 +549,6 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
mi_mark_crashed(file); mi_mark_crashed(file);
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
} }
if (!error)
{
if (param.out_flag & (O_NEW_DATA | O_NEW_INDEX))
{
bool in_auto_repair;
/*
We have to close all instances of this file to ensure that we can
do the rename safely on all operating system and to ensure that
all threads are using the new version.
*/
thd->proc_info="renaming file";
VOID(pthread_mutex_lock(&LOCK_open));
if (!(in_auto_repair = (table->table_cache_key == 0)))
{
if (close_cached_table(thd,table))
error=1;
}
else
{
if (param.out_flag & O_NEW_DATA)
my_close(file->dfile,MYF(0));
if (param.out_flag & O_NEW_INDEX)
my_close(file->s->kfile,MYF(0));
}
if (param.out_flag & O_NEW_DATA)
error|=change_to_newfile(fixed_name,MI_NAME_DEXT,
DATA_TMP_EXT, 0,
(param.testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0)));
if (param.out_flag & O_NEW_INDEX)
error|=change_to_newfile(fixed_name,MI_NAME_IEXT,
INDEX_TMP_EXT, 0, MYF(0));
if (in_auto_repair)
{
if ((param.out_flag & O_NEW_DATA) && mi_open_datafile(file,file->s))
error=1;
if ((param.out_flag & O_NEW_DATA) && mi_open_keyfile(file->s))
error=1;
}
VOID(pthread_mutex_unlock(&LOCK_open));
}
}
thd->proc_info=old_proc_info; thd->proc_info=old_proc_info;
DBUG_RETURN(error ? HA_ADMIN_FAILED : DBUG_RETURN(error ? HA_ADMIN_FAILED :
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK); !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
...@@ -634,8 +605,7 @@ bool ha_myisam::check_and_repair(THD *thd) ...@@ -634,8 +605,7 @@ bool ha_myisam::check_and_repair(THD *thd)
if (mi_is_crashed(file) || check(thd, &check_opt)) if (mi_is_crashed(file) || check(thd, &check_opt))
{ {
sql_print_error("Warning: Recovering table: %s",table->path); sql_print_error("Warning: Recovering table: %s",table->path);
if (check_opt.retry_without_quick) check_opt.quick= !check_opt.retry_without_quick;
check_opt.quick=0;
check_opt.flags=(((myisam_recover_options & HA_RECOVER_BACKUP) ? check_opt.flags=(((myisam_recover_options & HA_RECOVER_BACKUP) ?
T_BACKUP_DATA : 0) | T_BACKUP_DATA : 0) |
(!(myisam_recover_options & HA_RECOVER_FORCE) ? (!(myisam_recover_options & HA_RECOVER_FORCE) ?
......
...@@ -889,6 +889,24 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -889,6 +889,24 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
continue; continue;
} }
/* Close all instances of the table to allow repair to rename files */
if (open_for_modify && table->table->version)
{
pthread_mutex_lock(&LOCK_open);
mysql_lock_abort(thd,table->table);
while (remove_table_from_cache(thd, table->table->table_cache_key,
table->table->real_name) &&
! thd->killed)
{
dropping_tables++;
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
dropping_tables--;
}
pthread_mutex_unlock(&LOCK_open);
if (thd->killed)
goto err;
}
int result_code = (table->table->file->*operator_func)(thd, check_opt); int result_code = (table->table->file->*operator_func)(thd, check_opt);
packet->length(0); packet->length(0);
net_store_data(packet, table_name); net_store_data(packet, table_name);
...@@ -933,7 +951,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -933,7 +951,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
break; break;
} }
if (fatal_error) if (fatal_error)
table->table->flush_version=0; // Force close of table table->table->version=0; // Force close of table
close_thread_tables(thd); close_thread_tables(thd);
if (my_net_write(&thd->net, (char*) packet->ptr(), if (my_net_write(&thd->net, (char*) packet->ptr(),
packet->length())) packet->length()))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment