YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/* Setuptransactionhandlersothatwecanseeallrows.Whenrowsisread wewillcheckthefoundidagainstparam->max_tried
*/ if (!info->s->base.born_transactional)
{ /* Therearenotrids.Howeverwewanttosetmax_tridtomaketestof create_tridsimpler.
*/
param->max_trid= ~(TrID) 0;
} elseif (param->max_trid == 0 || param->max_trid == ~(TrID) 0)
{ if (!ma_control_file_inited())
param->max_trid= 0; /* Give warning for first trid found */ else
param->max_trid= max_trid_in_system();
}
maria_ignore_trids(info);
}
/* Check the status flags for the table */
int maria_chk_status(HA_CHECK *param, MARIA_HA *info)
{
MARIA_SHARE *share= info->s;
/* Protection for HA_EXTRA_FLUSH */
mysql_mutex_lock(&share->intern_lock);
if (maria_is_crashed_on_repair(info))
_ma_check_print_warning(param, "Table is marked as crashed and last repair failed"); elseif (maria_in_repair(info))
_ma_check_print_warning(param, "Last repair was aborted before finishing"); elseif (maria_is_crashed(info))
_ma_check_print_warning(param, "Table is marked as crashed"); if (share->state.open_count != (uint) (share->global_changed ? 1 : 0))
{ /* Don't count this as a real warning, as check can correct this ! */
my_bool save=param->warning_printed;
_ma_check_print_warning(param,
share->state.open_count==1 ? "%d client is using or hasn't closed the table properly" : "%d clients are using or haven't closed the table properly",
share->state.open_count); /* If this will be fixed by the check, forget the warning */ if (param->testflag & T_UPDATE_STATE)
param->warning_printed=save;
}
mysql_mutex_unlock(&share->intern_lock);
if (share->state.create_trid > param->max_trid)
{
param->wrong_trd_printed= 1; /* Force should run zerofill */
_ma_check_print_warning(param, "Table create_trd (%llu) > current max_transaction id (%llu). Table needs to be repaired or zerofilled to be usable",
share->state.create_trid, param->max_trid); return1;
} return0;
}
int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
{
MARIA_SHARE *share= info->s; int error; register my_off_t skr,size; char buff[22],buff2[22];
DBUG_ENTER("maria_chk_size");
if (info->s3)
{ /* We cannot check file sizes for S3 */
DBUG_RETURN(0);
} /* We should never come here with internal temporary tables */
DBUG_ASSERT(!share->internal_table);
if (!(param->testflag & T_SILENT))
puts("- check file-size");
/* Thefollowingisneededifcalledexternally(notfrommaria_chk). Togetacorrectphysicalsizeweneedtoflushthem.
*/ if ((error= _ma_flush_table_files(info,
MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE)))
_ma_check_print_error(param, "Failed to flush data or index file");
size= mysql_file_seek(share->kfile.file, 0L, MY_SEEK_END, MYF(MY_THREADSAFE)); if ((skr=(my_off_t) share->state.state.key_file_length) != size)
{ /* Don't give error if file generated by maria_pack */ if (skr > size && maria_is_any_key_active(share->state.key_map))
{
error=1;
_ma_check_print_error(param, "Size of indexfile is: %-8s Expected: %s",
llstr(size,buff), llstr(skr,buff2));
share->state.state.key_file_length= size;
} elseif (!(param->testflag & T_VERY_SILENT))
_ma_check_print_warning(param, "Size of indexfile is: %-8s Expected: %s",
llstr(size,buff), llstr(skr,buff2));
} if (size > share->base.max_key_file_length)
{
_ma_check_print_warning(param, "Size of indexfile is: %-8s which is bigger than max indexfile size: %s",
ullstr(size,buff),
ullstr(share->base.max_key_file_length, buff2));
} elseif (!(param->testflag & T_VERY_SILENT) &&
! (share->options & HA_OPTION_COMPRESS_RECORD) &&
ulonglong2double(share->state.state.key_file_length) >
ulonglong2double(share->base.margin_key_file_length)*0.9)
_ma_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
llstr(share->state.state.key_file_length,buff),
llstr(share->base.max_key_file_length,buff));
size= mysql_file_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
skr=(my_off_t) share->state.state.data_file_length; if (share->options & HA_OPTION_COMPRESS_RECORD)
skr+= MEMMAP_EXTRA_MARGIN; #ifdef USE_RELOC if (share->data_file_type == STATIC_RECORD &&
skr < (my_off_t) share->base.reloc*share->base.min_pack_length)
skr=(my_off_t) share->base.reloc*share->base.min_pack_length; #endif if (skr != size)
{
share->state.state.data_file_length=size; /* Skip other errors */ if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
{
error=1;
_ma_check_print_error(param,"Size of datafile is: %-9s Expected: %s",
llstr(size,buff), llstr(skr,buff2));
param->testflag|=T_RETRY_WITHOUT_QUICK;
} else
{
_ma_check_print_warning(param, "Size of datafile is: %-9s Expected: %s",
llstr(size,buff), llstr(skr,buff2));
}
} if (size > share->base.max_data_file_length)
{
_ma_check_print_warning(param, "Size of datafile is: %-8s which is bigger than max datafile size: %s",
ullstr(size,buff),
ullstr(share->base.max_data_file_length, buff2));
} elseif (!(param->testflag & T_VERY_SILENT) &&
!(share->options & HA_OPTION_COMPRESS_RECORD) &&
ulonglong2double(share->state.state.data_file_length) >
(ulonglong2double(share->base.max_data_file_length)*0.9))
_ma_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
llstr(share->state.state.data_file_length,buff),
llstr(share->base.max_data_file_length,buff2));
DBUG_RETURN(error);
} /* maria_chk_size */
if ((!(param->testflag & T_SILENT)))
printf ("- check data record references index: %d\n",key+1); if (keyinfo->key_alg > HA_KEY_ALG_BTREE)
full_text_keys++; if (share->state.key_root[key] == HA_OFFSET_ERROR)
{ if (share->state.state.records != 0 && keyinfo->key_alg != HA_KEY_ALG_FULLTEXT)
_ma_check_print_error(param, "Key tree %u is empty", key + 1); goto do_stat;
} if (_ma_fetch_keypage(&page, info, keyinfo, share->state.key_root[key],
PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
info->buff, 0))
{
report_keypage_fault(param, info, share->state.key_root[key]); if (!(param->testflag & T_INFO))
DBUG_RETURN(-1);
result= -1; continue;
}
param->key_file_blocks+=keyinfo->block_length;
keys=0;
param->keydata=param->totaldata=0;
param->key_blocks=0;
param->max_level=0; if (chk_index(param, info,keyinfo, &page, &keys, param->key_crc+key,1))
DBUG_RETURN(-1); if ((param->testflag & T_WRITE_LOOP) && param->verbose)
{
puts(" \r");
fflush(stdout);
} if (keyinfo->key_alg <= HA_KEY_ALG_BTREE)
{ if (keys != share->state.state.records)
{
_ma_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
llstr(share->state.state.records,buff2)); if (!(param->testflag & (T_INFO | T_EXTEND)))
DBUG_RETURN(-1);
result= -1; continue;
} if ((found_keys - full_text_keys == 1 &&
!(share->data_file_type == STATIC_RECORD)) ||
(param->testflag & T_DONT_CHECK_CHECKSUM))
old_record_checksum= param->record_checksum; elseif (old_record_checksum != param->record_checksum)
{ if (key)
_ma_check_print_error(param, "Key %u doesn't point at same records as " "key 1",
key+1); else
_ma_check_print_error(param,"Key 1 doesn't point at all records"); if (!(param->testflag & T_INFO))
DBUG_RETURN(-1);
result= -1; continue;
}
} if ((uint) share->base.auto_key -1 == key)
{ /* Check that auto_increment key is bigger than max key value */
ulonglong auto_increment; const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
info->lastinx=key;
_ma_read_key_record(info, info->rec_buff, 0);
auto_increment=
ma_retrieve_auto_increment(info->rec_buff + keyseg->start,
keyseg->type); if (auto_increment > share->state.auto_increment)
{
_ma_check_print_warning(param, "Auto-increment value: %s is smaller " "than max used value: %s",
llstr(share->state.auto_increment,buff2),
llstr(auto_increment, buff));
} if (param->testflag & T_AUTO_INC)
{
set_if_bigger(share->state.auto_increment,
auto_increment);
set_if_bigger(share->state.auto_increment,
param->auto_increment_value);
}
/* Check that there isn't a row with auto_increment = 0 in the table */
maria_extra(info,HA_EXTRA_KEYREAD,0);
bzero(info->lastkey_buff, keyinfo->seg->length); if (!maria_rkey(info, info->rec_buff, key,
info->lastkey_buff,
(key_part_map) 1, HA_READ_KEY_EXACT))
{ /* Don't count this as a real warning, as maria_chk can't correct it */
my_bool save=param->warning_printed;
_ma_check_print_warning(param, "Found row where the auto_increment " "column has the value 0");
param->warning_printed=save;
}
maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
}
param->keydata+= anc_page->size;
param->totaldata+= keyinfo->block_length; /* INFO */
param->key_blocks++; if (level > param->max_level)
param->max_level=level;
if (_ma_get_keynr(share, anc_page->buff) != keyinfo->key_nr)
_ma_check_print_error(param, "Page at %s is not marked for index %u",
llstr(anc_page->pos, llbuff),
(uint) keyinfo->key_nr); if (page_flag & KEYPAGE_FLAG_HAS_TRANSID)
{ if (!share->base.born_transactional)
{
_ma_check_print_error(param, "Page at %s is marked with HAS_TRANSID even if " "table is not transactional",
llstr(anc_page->pos, llbuff));
}
} if (share->base.born_transactional)
{
LSN lsn= lsn_korr(anc_page->buff); if ((ulonglong) lsn > param->max_allowed_lsn)
{ /* Avoid flooding of errors */ if (param->skip_lsn_error_count++ < MAX_LSN_ERRORS)
{
_ma_check_print_error(param, "Page at %s as wrong LSN " LSN_FMT ". Current " "LSN is " LSN_FMT,
llstr(anc_page->pos, llbuff),
LSN_IN_PARTS(lsn),
LSN_IN_PARTS(param->max_allowed_lsn));
}
}
} if (anc_page->size > share->max_index_block_size)
{
_ma_check_print_error(param, "Page at %s has impossible (too big) pagelength",
llstr(anc_page->pos, llbuff)); goto err;
}
info->last_key.keyinfo= tmp_key.keyinfo= keyinfo;
info->lastinx= ~0; /* Safety */
tmp_key.data= tmp_key_buff; for ( ;; _ma_copy_key(&info->last_key, &tmp_key))
{ if (nod_flag)
{ if (_ma_killed_ptr(param)) goto err;
next_page= _ma_kpos(nod_flag,keypos); if (chk_index_down(param,info,keyinfo,next_page,
temp_buff,keys,key_checksum,level+1))
{
DBUG_DUMP("page_data", old_keypos, (uint) (keypos - old_keypos)); goto err;
}
}
old_keypos=keypos; if (keypos >= endpos ||
!(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos)) break; if (keypos > endpos)
{
_ma_check_print_error(param, "Page length and length of keys don't match at " "page: %s",
llstr(anc_page->pos,llbuff)); goto err;
} if (share->data_file_type == BLOCK_RECORD &&
!(page_flag & KEYPAGE_FLAG_HAS_TRANSID) &&
key_has_transid(tmp_key.data + tmp_key.data_length +
share->rec_reflength-1))
{
_ma_check_print_error(param, "Found key marked for transid on page that is not " "marked for transid at: %s",
llstr(anc_page->pos,llbuff)); goto err;
}
if ((comp_flag & SEARCH_FIND) && flag == 0)
_ma_check_print_error(param,"Found duplicated key at page %s",
llstr(anc_page->pos,llbuff)); else
_ma_check_print_error(param,"Key in wrong position at page %s",
llstr(anc_page->pos,llbuff)); goto err;
}
_ma_check_print_error(param, "Bitmap at page %s has pages reserved outside of " "data file length",
llstr(bitmap_page, llbuff));
DBUG_EXECUTE("bitmap", _ma_print_bitmap(&share->bitmap, bitmap_buff,
bitmap_page););
}
}
_ma_scan_end_block_record(info);
if (full_page_count != param->full_page_count)
_ma_check_print_error(param, "Full page count read through records was %s " "but we found %s pages while scanning table",
llstr(param->full_page_count, llbuff),
llstr(full_page_count, llbuff2)); if (tail_count != param->tail_count)
_ma_check_print_error(param, "Tail count read through records was %s but " "we found %s tails while scanning table",
llstr(param->tail_count, llbuff),
llstr(tail_count, llbuff2));
info->in_check_table= 1; /* Don't assert on checksum errors */
switch (share->data_file_type) { case BLOCK_RECORD:
error= check_block_record(param, info, extend, record); break; case STATIC_RECORD:
error= check_static_record(param, info, extend, record); break; case DYNAMIC_RECORD:
error= check_dynamic_record(param, info, extend, record); break; case COMPRESSED_RECORD:
error= check_compressed_record(param, info, extend, record); break; case NO_RECORD:
param->records= share->state.state.records;
param->record_checksum= 0;
extend= 1; /* No row checksums */ /* no data, nothing to do */ break;
} /* switch */
info->in_check_table= 0;
if (error) goto err;
if (param->testflag & T_WRITE_LOOP)
{
fputs(" \r",stdout);
fflush(stdout);
} if (param->records != share->state.state.records)
{
_ma_check_print_error(param, "Record-count is not ok; found %-10s Should be: %s",
llstr(param->records,llbuff),
llstr(share->state.state.records,llbuff2));
error=1;
} if (param->record_checksum &&
param->record_checksum != param->tmp_record_checksum)
{
_ma_check_print_error(param, "Key pointers and record positions doesn't match");
error=1;
} if (param->glob_crc != share->state.state.checksum &&
(share->options &
(HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
{
_ma_check_print_warning(param, "Record checksum is not the same as checksum " "stored in the index file");
error=1;
} if (!extend)
{
uint key; for (key=0 ; key < share->base.keys; key++)
{ if (param->tmp_key_crc[key] != param->key_crc[key] &&
share->keyinfo[key].key_alg <= HA_KEY_ALG_BTREE)
{
_ma_check_print_error(param,"Checksum for key: %2d doesn't match " "checksum for records",
key+1);
error=1;
}
}
}
if (param->del_length != share->state.state.empty)
{
_ma_check_print_warning(param, "Found %s deleted space. Should be %s",
llstr(param->del_length,llbuff2),
llstr(share->state.state.empty,llbuff));
} /* Skip following checks for BLOCK RECORD as they don't make any sence */ if (share->data_file_type != BLOCK_RECORD)
{ if (param->used + param->empty + param->del_length !=
share->state.state.data_file_length)
{
_ma_check_print_warning(param, "Found %s record data and %s unused data and %s " "deleted data",
llstr(param->used, llbuff),
llstr(param->empty,llbuff2),
llstr(param->del_length,llbuff3));
_ma_check_print_warning(param, "Total %s Should be: %s",
llstr((param->used+param->empty +
param->del_length), llbuff),
llstr(share->state.state.data_file_length,
llbuff2));
} if (param->del_blocks != share->state.state.del)
{
_ma_check_print_warning(param, "Found %10s deleted blocks. Should be: %s",
llstr(param->del_blocks,llbuff),
llstr(share->state.state.del,llbuff2));
} if (param->splits != share->state.split)
{
_ma_check_print_warning(param, "Found %10s parts. Should be: %s",
llstr(param->splits, llbuff),
llstr(share->state.split,llbuff2));
}
} if (param->testflag & T_INFO)
{ if (param->warning_printed || param->error_printed)
puts(""); if (param->used != 0 && ! param->error_printed)
{ if (param->records)
{
printf("Records:%18s M.recordlength:%9lu Packed:%14.0f%%\n",
llstr(param->records,llbuff),
(long)((param->used - param->link_used)/param->records),
(share->base.blobs ? 0.0 :
(ulonglong2double((ulonglong) share->base.reclength *
param->records)-
my_off_t2double(param->used))/
ulonglong2double((ulonglong) share->base.reclength *
param->records)*100.0));
printf("Recordspace used:%9.0f%% Empty space:%12d%% " "Blocks/Record: %6.2f\n",
(ulonglong2double(param->used - param->link_used)/
ulonglong2double(param->used-param->link_used+param->empty) * 100.0),
(!param->records ? 100 :
(int) (ulonglong2double(param->del_length+param->empty)/
my_off_t2double(param->used)*100.0)),
ulonglong2double(param->splits - param->del_blocks) /
param->records);
} else
printf("Records:%18s\n", "0");
}
printf("Record blocks:%12s Delete blocks:%10s\n",
llstr(param->splits - param->del_blocks, llbuff),
llstr(param->del_blocks, llbuff2));
printf("Record data: %12s Deleted data: %10s\n",
llstr(param->used - param->link_used,llbuff),
llstr(param->del_length, llbuff2));
printf("Empty space: %12s Linkdata: %10s\n",
llstr(param->empty, llbuff),llstr(param->link_used, llbuff2)); if (share->data_file_type == BLOCK_RECORD)
{
printf("Full pages: %12s Tail count: %12s\n",
llstr(param->full_page_count, llbuff),
llstr(param->tail_count, llbuff2));
printf("Lost space: %12s\n", llstr(param->lost, llbuff)); if (param->max_found_trid)
{
printf("Max trans. id: %11s\n",
llstr(param->max_found_trid, llbuff));
}
}
}
my_free(record);
DBUG_RETURN (error);
if (share->data_file_type == NO_RECORD)
{
_ma_check_print_error(param, "Can't repair tables with record type NO_DATA"); return1;
}
/* Make a copy to allow us to restore state and check how state changed */
memcpy(org_share, share, sizeof(*share));
/* Repair code relies on share->state.state so we have to update it here */ if (share->lock.update_status)
(*share->lock.update_status)(info->lock.status_param);
param->testflag|= T_REP; /* for easy checking */ if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
param->testflag|= T_CALC_CHECKSUM;
param->glob_crc= 0; if (rep_quick)
param->testflag|= T_QUICK; else
param->testflag&= ~T_QUICK;
param->org_key_map= share->state.key_map;
if (protect_against_repair_crash(info, param,
!MY_TEST(param->testflag &
T_CREATE_MISSING_KEYS))) return1;
/* calculate max_records */ if (!share->internal_table)
{ /* Get real file size */
sort_info->filelength= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
} else
{ /* For internal temporary files we are using the logical file length */
sort_info->filelength= share->state.state.data_file_length;
}
/* We don't need a bigger sort buffer than file_length * 8 */
threads= (param->testflag & T_REP_PARALLEL) ? (uint) share->base.keys : 1;
tmp= (size_t) MY_MIN(sort_info->filelength,
(my_off_t) (SIZE_T_MAX/10/threads));
tmp= MY_MAX(tmp * 8 * threads, (size_t) 65536); /* Some margin */
param->sort_buffer_length= MY_MIN(param->orig_sort_buffer_length, tmp);
set_if_bigger(param->sort_buffer_length, MARIA_MIN_SORT_MEMORY); /* Protect against too big sort buffer length */ #if SIZEOF_SIZE_T >= 8
set_if_smaller(param->sort_buffer_length, 16LL*1024LL*1024LL*1024LL); #else
set_if_smaller(param->sort_buffer_length, 1L*1024L*1024L*1024L); #endif
/* Set up transaction handler so that we can see all rows */ if (param->max_trid == 0)
{ if (!ma_control_file_inited())
param->max_trid= 0; /* Give warning for first trid found */ else
param->max_trid= max_trid_in_system();
}
maria_ignore_trids(info); /* Don't write transid's during repair */
maria_versioning(info, 0); /* remember original number of rows */
*info->state= info->s->state.state; if (share->data_file_type == BLOCK_RECORD)
share->state.state.data_file_length= MY_ALIGN(sort_info->filelength,
(my_off_t) share->block_size); else
share->state.state.data_file_length= sort_info->filelength; return0;
}
/* Flush obsolete index data from key cache */
_ma_flush_table_files(info, MARIA_FLUSH_INDEX,
FLUSH_IGNORE_CHANGED, FLUSH_IGNORE_CHANGED); /* 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. */
share->state.state.key_file_length= share->base.keystart;
if (org_data_file_type != BLOCK_RECORD)
{ /* We need a read buffer to read rows in big blocks */ if (init_io_cache(¶m->read_cache, info->dfile.file,
(uint) param->read_buffer_length,
READ_CACHE, share->pack.header_length, 1, MYF(MY_WME))) goto err;
} if (!block_record)
{ /* When writing to not block records, we need a write buffer */ if (!rep_quick)
{ if (init_io_cache(&sort_info.new_info->rec_cache, new_file,
(uint) param->write_buffer_length,
WRITE_CACHE, new_header_length, 1,
MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)) goto err;
sort_info.new_info->opt_flag|=WRITE_CACHE_USED;
}
} else
{
scan_inited= 1; if (maria_scan_init(sort_info.info)) goto err;
}
if (!(sort_param.record=
(uchar *) my_malloc(PSI_INSTRUMENT_ME, (uint)
share->base.default_rec_buff_size,
MYF(MY_THREAD_SPECIFIC))) ||
_ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
share->base.default_rec_buff_size,
MYF(MY_THREAD_SPECIFIC)))
{
_ma_check_print_error(param, "Not enough memory for extra record"); goto err;
}
if (param->testflag & T_CREATE_MISSING_KEYS)
maria_set_all_keys_active(share->state.key_map, share->base.keys);
maria_drop_all_indexes(param, info, TRUE);
maria_lock_memory(param); /* Everything is alloced */
sort_param.sort_info->info->in_check_table= 1; /* Re-create all keys, which are set in key_map. */ while (!(error=sort_get_next_record(&sort_param)))
{ if (block_record && _ma_sort_write_record(&sort_param)) goto err;
if (writekeys(&sort_param))
{ if (my_errno != HA_ERR_FOUND_DUPP_KEY) goto err;
DBUG_DUMP("record", 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,
record_pos_to_txt(info,
sort_param.current_filepos,
llbuff),
record_pos_to_txt(info,
info->dup_key_pos, llbuff2)); if (param->testflag & T_VERBOSE)
{
MARIA_KEY tmp_key;
MARIA_KEYDEF *keyinfo= share->keyinfo + info->errkey;
(*keyinfo->make_key)(info, &tmp_key, (uint) info->errkey,
info->lastkey_buff,
sort_param.record, 0L, 0);
_ma_print_key(stdout, &tmp_key);
}
sort_info.dupp++; if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
{
param->testflag|=T_RETRY_WITHOUT_QUICK;
param->error_printed++; goto err;
} /* purecov: begin tested */ if (block_record)
{
sort_info.new_info->s->state.state.records--; if ((*sort_info.new_info->s->write_record_abort)(sort_info.new_info))
{
_ma_check_print_error(param,"Couldn't delete duplicate row"); goto err;
}
} /* purecov: end */ continue;
} if (!block_record)
{ if (_ma_sort_write_record(&sort_param)) goto err; /* Filepos is pointer to where next row will be stored */
sort_param.current_filepos= sort_param.filepos;
}
} if (error > 0 || maria_write_data_suffix(&sort_info, !rep_quick) ||
flush_io_cache(&sort_info.new_info->rec_cache) ||
param->read_cache.error < 0) goto err;
if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: " "Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
param->retry_repair=1;
param->testflag|=T_RETRY_WITHOUT_QUICK; goto err;
}
if (param->testflag & T_SAFE_REPAIR)
{ /* Don't repair if we lost more than one row */ if (sort_info.new_info->s->state.state.records+1 < start_records)
{
share->state.state.records= start_records; goto err;
}
}
if (!rep_quick)
{
sort_info.new_info->s->state.state.data_file_length= sort_param.filepos; if (sort_info.new_info != sort_info.info)
{
MARIA_STATE_INFO save_state= sort_info.new_info->s->state; if (maria_close(sort_info.new_info))
{
_ma_check_print_error(param, "Got error %d on close", my_errno); goto err;
}
copy_data_file_state(&share->state, &save_state);
new_file= -1;
sort_info.new_info= info;
}
share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
/* Replace the actual file with the temporary file */ if (new_file >= 0)
mysql_file_close(new_file, MYF(MY_WME));
new_file= -1;
change_data_file_descriptor(info, -1); if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
DATA_TMP_EXT, param->backup_time,
(param->testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0)) |
sync_dir) ||
_ma_open_datafile(info, share))
{ goto err;
}
} else
{
share->state.state.data_file_length= sort_param.max_pos;
} if (param->testflag & T_CALC_CHECKSUM)
share->state.state.checksum= param->glob_crc;
if (!(param->testflag & T_SILENT))
{ if (start_records != share->state.state.records)
printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
} if (sort_info.dupp)
_ma_check_print_warning(param, "%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error= 0; /* If invoked by external program that uses thr_lock */ if (&share->state.state != info->state)
*info->state= *info->state_start= share->state.state;
err: if (scan_inited)
maria_scan_end(sort_info.info);
_ma_reset_state(info);
sort_param.sort_info->info->in_check_table= 0; /* this below could fail, shouldn't we detect error? */ if (got_error)
{ if (! param->error_printed)
_ma_check_print_error(param,"Got error %d for record at pos %s when creating index",
my_errno,
llstr(sort_param.start_recpos,llbuff));
(void)_ma_flush_table_files_before_swap(param, info); if (sort_info.new_info && sort_info.new_info != sort_info.info)
{
unuse_data_file_descriptor(sort_info.new_info);
maria_close(sort_info.new_info);
} if (new_file >= 0)
{
mysql_file_close(new_file,MYF(0));
mysql_file_delete(key_file_tmp, param->temp_filename, MYF(MY_WME));
}
maria_mark_crashed_on_repair(info);
} /* If caller had disabled logging it's not up to us to re-enable it */ if (reenable_logging)
_ma_reenable_logging_for_table(info, FALSE);
restore_table_state_after_repair(info, &backup_share);
for (i=0 ; i < share->base.keys ; i++)
{ if (maria_is_key_active(share->state.key_map, i))
{ if (share->keyinfo[i].key_alg == HA_KEY_ALG_FULLTEXT)
{ if (_ma_ft_add(info, i, key_buff, record, filepos)) goto err;
} else
{ if (!(*share->keyinfo[i].make_key)(info, &key, i, key_buff, record,
filepos, 0)) goto err; if ((*share->keyinfo[i].ck_insert)(info, &key)) goto err;
}
}
}
DBUG_RETURN(0);
err: if (my_errno == HA_ERR_FOUND_DUPP_KEY)
{
info->errkey=(int) i; /* This key was found */ while ( i-- > 0 )
{ if (maria_is_key_active(share->state.key_map, i))
{ if (share->keyinfo[i].key_alg == HA_KEY_ALG_FULLTEXT)
{ if (_ma_ft_del(info,i,key_buff,record,filepos)) break;
} else
{
(*share->keyinfo[i].make_key)(info, &key, i, key_buff, record,
filepos, 0); if (_ma_ck_delete(info, &key)) break;
}
}
}
} /* Remove checksum that was added to glob_crc in sort_get_next_record */ if (sort_param->calc_checksum)
sort_param->sort_info->param->glob_crc-= info->cur_row.checksum;
DBUG_PRINT("error",("errno: %d",my_errno));
DBUG_RETURN(-1);
} /* writekeys */
/* Change all key-pointers that points to a records */
/* cannot sort index files with R-tree indexes */ for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
key++,keyinfo++) if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
DBUG_RETURN(0);
if (!(param->testflag & T_SILENT))
printf("- Sorting index for Aria-table '%s'\n",name);
if (protect_against_repair_crash(info, param, FALSE))
DBUG_RETURN(1);
/* Get real path for index file */
fn_format(param->temp_filename,name,"", MARIA_NAME_IEXT,2+4+32); if ((new_file=mysql_file_create(key_file_kfile, fn_format(param->temp_filename,param->temp_filename, "", INDEX_TMP_EXT,2+4), 0, param->tmpfile_createflag, MYF(0))) < 0)
{
_ma_check_print_error(param,"Can't create new tempfile: '%s'",
param->temp_filename);
DBUG_RETURN(-1);
} if (maria_filecopy(param, new_file, share->kfile.file, 0L,
(ulong) share->base.keystart, "headerblock")) goto err;
param->new_file_pos=share->base.keystart; for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
key++,keyinfo++)
{ if (maria_is_key_active(share->state.key_map, key) &&
share->state.key_root[key] != HA_OFFSET_ERROR)
{
index_pos[key]=param->new_file_pos; /* Write first block here */ if (sort_one_index(param,info,keyinfo,share->state.key_root[key],
new_file)) goto err;
} else
index_pos[key]= HA_OFFSET_ERROR; /* No blocks */
}
/* Flush key cache for this file if we are calling this outside maria_chk */
flush_pagecache_blocks(share->pagecache, &share->kfile,
FLUSH_IGNORE_CHANGED);
share->state.version=(ulong) time((time_t*) 0);
old_state= share->state; /* save state if not stored */
r_locks= share->r_locks;
w_locks= share->w_locks;
old_lock= info->lock_type;
/* Put same locks as old file */
share->r_locks= share->w_locks= share->tot_locks= 0;
(void) _ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
mysql_mutex_lock(&share->intern_lock);
mysql_file_close(share->kfile.file, MYF(MY_WME));
share->kfile.file = -1;
mysql_mutex_unlock(&share->intern_lock);
mysql_file_close(new_file, MYF(MY_WME)); if (maria_change_to_newfile(share->index_file_name.str, MARIA_NAME_IEXT,
INDEX_TMP_EXT, 0, sync_dir) ||
_ma_open_keyfile(share)) goto err2;
info->lock_type= F_UNLCK; /* Force maria_readinfo to lock */
_ma_readinfo(info,F_WRLCK,0); /* Will lock the table */
info->lock_type= old_lock;
share->r_locks= r_locks;
share->w_locks= w_locks;
share->tot_locks= r_locks+w_locks;
share->state= old_state; /* Restore old state */
/* cannot walk over R-tree indices */
DBUG_ASSERT(keyinfo->key_alg != HA_KEY_ALG_RTREE);
new_page_pos=param->new_file_pos;
param->new_file_pos+=keyinfo->block_length;
key.keyinfo= keyinfo;
alloc_on_stack(*param->stack_end_ptr, buff, buff_alloced,
keyinfo->block_length + keyinfo->max_store_length); if (!buff)
{
_ma_check_print_error(param,"Not enough memory for keyblock");
DBUG_RETURN(-1);
}
key.data= buff + keyinfo->block_length;
for ( ;; )
{ if (nod_flag)
{
next_page= _ma_kpos(nod_flag,keypos); /* Save new pos */
_ma_kpointer(info,keypos-nod_flag,param->new_file_pos); if (sort_one_index(param,info,keyinfo,next_page,new_file))
{
DBUG_PRINT("error",
("From page: %ld, keyoffset: %lu used_length: %d",
(ulong) pagepos, (ulong) (keypos - buff),
(int) page.size));
DBUG_DUMP("buff", page.buff, page.size); goto err;
}
} if (keypos >= endpos ||
!(*keyinfo->get_key)(&key, page.flag, nod_flag, &keypos)) break;
DBUG_ASSERT(keypos <= endpos); if (keyinfo->key_alg == HA_KEY_ALG_FULLTEXT)
{
uint off; int subkeys;
get_key_full_length_rdonly(off, key.data);
subkeys= ft_sintXkorr(key.data + off); if (subkeys < 0)
{
next_page= _ma_row_pos_from_key(&key);
_ma_dpointer(share, keypos - nod_flag - share->rec_reflength,
param->new_file_pos); /* Save new pos */ if (sort_one_index(param,info,&share->ft2_keyinfo,
next_page,new_file)) goto err;
}
}
}
}
/* Fill block with zero and write it to the new index file */
length= page.size;
bzero(buff+length,keyinfo->block_length-length); if (write_page(share, new_file, buff, keyinfo->block_length,
new_page_pos, MYF(MY_NABP | MY_WAIT_IF_FULL) & param->myf_rw))
{
_ma_check_print_error(param,"Can't write indexblock, error: %d",my_errno); goto err;
}
stack_alloc_free(buff, buff_alloced);
DBUG_RETURN(0);
err:
stack_alloc_free(buff, buff_alloced);
DBUG_RETURN(1);
} /* sort_one_index */
/* This works only with BLOCK_RECORD files */ if (share->data_file_type != BLOCK_RECORD)
DBUG_RETURN(0);
if (!(param->testflag & T_SILENT))
printf("- Zerofilling data for Aria-table '%s'\n",name);
/* Go through the record file */ for (page= 1, pos= block_size;
pos < share->state.state.data_file_length;
pos+= block_size, page++)
{
uchar *buff; enum en_page_type page_type;
/* Ignore bitmap pages */ if ((page % share->bitmap.pages_covered) == 0) continue; if (!(buff= pagecache_read(share->pagecache,
&info->dfile,
page, 1, 0,
read_page_type, PAGECACHE_LOCK_WRITE,
&page_link.link)))
{
_ma_check_print_error(param, "Page %9s: Got error: %d when reading datafile",
llstr(pos, llbuff), my_errno); goto err;
}
page_type= (enum en_page_type) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK); switch (page_type) { case UNALLOCATED_PAGE: if (zero_lsn)
bzero(buff, block_size); else
bzero(buff + LSN_SIZE, block_size - LSN_SIZE); break; case BLOB_PAGE: if (_ma_bitmap_get_page_bits(info, bitmap, page) == 0)
{ /* Unallocated page */ if (zero_lsn)
bzero(buff, block_size); else
bzero(buff + LSN_SIZE, block_size - LSN_SIZE);
} else if (zero_lsn)
bzero(buff, LSN_SIZE); break; case HEAD_PAGE: case TAIL_PAGE:
{
uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
uint offset, dir_start, empty_space;
uchar *dir;
/* compactation may have increased free space */
empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET); if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */ if (_ma_bitmap_set(info, page, is_head_page,
empty_space)) goto err;
/* Zerofill the not used part */
offset= uint2korr(dir) + uint2korr(dir+2);
dir_start= (uint) (dir - buff);
DBUG_ASSERT(dir_start >= offset); if (dir_start > offset)
bzero(buff + offset, dir_start - offset);
} break;
} default:
_ma_check_print_error(param, "Page %9s: Found unrecognizable block of type %d",
llstr(pos, llbuff), page_type); goto err;
}
pagecache_unlock_by_link(share->pagecache, page_link.link,
PAGECACHE_LOCK_WRITE_UNLOCK,
PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
LSN_IMPOSSIBLE, 1, FALSE);
}
error= _ma_bitmap_flush(share); if (flush_pagecache_blocks(share->pagecache, &info->dfile,
FLUSH_FORCE_WRITE))
error= 1;
DBUG_RETURN(error);
err:
pagecache_unlock_by_link(share->pagecache, page_link.link,
PAGECACHE_LOCK_WRITE_UNLOCK,
PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
LSN_IMPOSSIBLE, 0, FALSE); /* flush what was changed so far */
(void) _ma_bitmap_flush(share);
(void) flush_pagecache_blocks(share->pagecache, &info->dfile,
FLUSH_FORCE_WRITE);
if (!error)
{ /* Markthatwehavedonezerofillofdataandindex.IfwezeroedtheLSN onthepages,tableismovable.
*/
share->state.changed&= ~STATE_NOT_ZEROFILLED; if (zero_lsn)
{
share->state.changed&= ~(STATE_NOT_MOVABLE | STATE_MOVED | STATE_HAS_LSN); /* Table should get new LSNs */
share->state.create_rename_lsn= share->state.is_of_horizon=
share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
} else
share->state.changed|= STATE_HAS_LSN; /* Ensure state is later flushed to disk, if within maria_chk */
info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
if (!rep_quick)
{ /* Get real path for data file */ if ((new_file=mysql_file_create(key_file_tmp,
fn_format(param->temp_filename,
share->data_file_name.str, "",
DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag,
MYF(0))) < 0)
{
_ma_check_print_error(param,"Can't create new tempfile: '%s'",
param->temp_filename); goto err;
} if (new_header_length &&
maria_filecopy(param, new_file, info->dfile.file, 0L,
new_header_length, "datafile-header")) goto err;
share->state.dellink= HA_OFFSET_ERROR;
info->rec_cache.file= new_file; /* For sort_delete_record */ if (share->data_file_type == BLOCK_RECORD ||
(param->testflag & T_UNPACK))
{ if (create_new_data_handle(&sort_param, new_file)) goto err;
sort_info.new_info->rec_cache.file= new_file;
}
}
if (!(sort_info.key_block=
alloc_key_blocks(param,
(uint) param->sort_key_blocks,
share->base.max_key_block_length))) goto err;
sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
if (share->data_file_type != BLOCK_RECORD)
{ /* We need a read buffer to read rows in big blocks */ if (init_io_cache(¶m->read_cache, info->dfile.file,
(uint) param->read_buffer_length,
READ_CACHE, org_header_length, 1, MYF(MY_WME))) goto err;
} if (sort_info.new_info->s->data_file_type != BLOCK_RECORD)
{ /* When writing to not block records, we need a write buffer */ if (!rep_quick)
{ if (init_io_cache(&sort_info.new_info->rec_cache, new_file,
(uint) param->write_buffer_length,
WRITE_CACHE, new_header_length, 1,
MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)) goto err;
sort_info.new_info->opt_flag|= WRITE_CACHE_USED;
}
}
if (!(sort_param.record=
(uchar*) my_malloc(PSI_INSTRUMENT_ME,
(size_t) share->base.default_rec_buff_size,
MYF(MY_THREAD_SPECIFIC))) ||
_ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
share->base.default_rec_buff_size,
MYF(MY_THREAD_SPECIFIC)))
{
_ma_check_print_error(param, "Not enough memory for extra record"); goto err;
}
/* 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)
{ /* Invert the copied key_map to recreate all disabled indexes. */
key_map= ~key_map;
}
/* Calculate number of keys to repair */
keys_to_repair= 0; for (sort_param.key=0 ; sort_param.key < share->base.keys ;
sort_param.key++)
{ if (maria_is_key_active(key_map, sort_param.key))
keys_to_repair++;
} /* For each key we scan and merge sort the keys */
param->max_stage= keys_to_repair*2;
rec_per_key_part= param->new_rec_per_key_part; for (sort_param.key=0 ; sort_param.key < share->base.keys ;
rec_per_key_part+=sort_param.keyinfo->keysegs, sort_param.key++)
{
sort_param.keyinfo=share->keyinfo+sort_param.key; /* Skipthisindexifitismarkeddisabledinthecopied (andpossiblyinverted)key_map.
*/ if (! maria_is_key_active(key_map, sort_param.key))
{ /* Remember old statistics for key */
memcpy((char*) rec_per_key_part,
(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;
}
if ((!(param->testflag & T_SILENT)))
printf ("- Fixing index %d\n",sort_param.key+1);
if (sort_info.new_info->s->data_file_type == BLOCK_RECORD)
{
scan_inited= 1; if (maria_scan_init(sort_info.info)) goto err;
} if (_ma_create_index_by_sort(&sort_param,
(my_bool) (!(param->testflag & T_VERBOSE)),
(size_t) param->sort_buffer_length))
{ if ((param->testflag & T_CREATE_UNIQUE_BY_SORT) && sort_param.sort_info->dupp)
share->state.dupp_key= sort_param.key; else
param->retry_repair= 1;
_ma_check_print_error(param, "Create index by sort failed"); goto err;
}
DBUG_EXECUTE_IF("maria_flush_whole_log",
{
DBUG_PRINT("maria_flush_whole_log", ("now"));
translog_flush(translog_get_horizon());
});
DBUG_EXECUTE_IF("maria_crash_create_index_by_sort",
{
DBUG_PRINT("maria_crash_create_index_by_sort", ("now"));
DBUG_SUICIDE();
}); if (scan_inited)
{
scan_inited= 0;
maria_scan_end(sort_info.info);
}
/* No need to calculate checksum again. */
sort_param.calc_checksum= 0;
free_root(&sort_param.wordroot, MYF(0));
/* Set for next loop */
sort_info.max_records= (ha_rows) sort_info.new_info->s->state.state.records;
param->stage++; /* Next stage */
param->progress= 0;
if (_ma_flush_table_files_before_swap(param, info)) goto err;
if (sort_param.fix_datafile)
{
param->read_cache.end_of_file=sort_param.filepos; if (maria_write_data_suffix(&sort_info,1) ||
end_io_cache(&sort_info.new_info->rec_cache))
{
_ma_check_print_error(param, "Got error when flushing row cache"); goto err;
}
sort_info.new_info->opt_flag&= ~WRITE_CACHE_USED;
if (param->testflag & T_SAFE_REPAIR)
{ /* Don't repair if we loosed more than one row */ if (sort_info.new_info->s->state.state.records+1 < start_records)
{
_ma_check_print_error(param, "Rows lost (Found %lu of %lu); Aborting " "because safe repair was requested",
(ulong) sort_info.new_info->s->
state.state.records,
(ulong) start_records);
share->state.state.records=start_records; goto err;
}
}
share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
/* Replace the actual file with the temporary file */ if (new_file >= 0)
{
mysql_file_close(new_file, MYF(MY_WME));
new_file= -1;
}
change_data_file_descriptor(info, -1); if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
DATA_TMP_EXT, param->backup_time,
(param->testflag & T_BACKUP_DATA ?
MYF(MY_REDEL_MAKE_BACKUP): MYF(0)) |
sync_dir) ||
_ma_open_datafile(info, share))
{
_ma_check_print_error(param, "Couldn't change to new data file"); goto err;
} /* Inform sort_delete_record that we are using the new file */
sort_info.new_info->dfile.file= info->rec_cache.file= info->dfile.file;
if (param->testflag & T_UNPACK)
restore_data_file_type(share);
if (param->testflag & T_CALC_CHECKSUM)
share->state.state.checksum=param->glob_crc;
if (!share->internal_table &&
mysql_file_chsize(share->kfile.file,
share->state.state.key_file_length, 0, MYF(0)) > 0)
_ma_check_print_warning(param, "Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT))
{ if (start_records != share->state.state.records)
printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
} if (sort_info.dupp)
_ma_check_print_warning(param, "%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0; /* If invoked by external program that uses thr_lock */ if (&share->state.state != info->state)
*info->state= *info->state_start= share->state.state;
err: if (scan_inited)
maria_scan_end(sort_info.info);
_ma_reset_state(info);
if (sort_info.new_info)
{
end_io_cache(&sort_info.new_info->rec_cache);
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
}
end_io_cache(¶m->read_cache);
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); if (got_error)
{ if (! param->error_printed)
_ma_check_print_error(param,"Got error %d when trying to repair table",my_errno);
(void)_ma_flush_table_files_before_swap(param, info); if (sort_info.new_info && sort_info.new_info != sort_info.info)
{
unuse_data_file_descriptor(sort_info.new_info);
maria_close(sort_info.new_info);
} if (new_file >= 0)
{
mysql_file_close(new_file, MYF(0));
mysql_file_delete(key_file_tmp, param->temp_filename, MYF(MY_WME));
}
maria_mark_crashed_on_repair(info);
} else
{ if (key_map == share->state.key_map)
share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS; /* Nowthatwehaveflushedandforcedeverything,wecanbump create_rename_lsn:
*/
DBUG_EXECUTE_IF("maria_flush_whole_log",
{
DBUG_PRINT("maria_flush_whole_log", ("now"));
translog_flush(translog_get_horizon());
});
DBUG_EXECUTE_IF("maria_crash_repair",
{
DBUG_PRINT("maria_crash_repair", ("now"));
DBUG_SUICIDE();
});
}
share->state.changed|= STATE_NOT_SORTED_PAGES; if (!rep_quick)
share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
STATE_NOT_MOVABLE);
/* If caller had disabled logging it's not up to us to re-enable it */ if (reenable_logging)
_ma_reenable_logging_for_table(info, FALSE);
restore_table_state_after_repair(info, &backup_share);
/* 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)
{ /* Invert the copied key_map to recreate all disabled indexes. */
key_map= ~key_map;
}
if (mysql_thread_create(key_thread_find_all_keys,
&sort_param[i].thr, &thr_attr,
_ma_thr_find_all_keys, (void *) (sort_param+i)))
{
_ma_check_print_error(param,"Cannot start a repair thread"); /* Cleanup: Detach from the share. Avoid others to be blocked. */ if (io_share.total_threads)
remove_io_thread(&sort_param[i].read_cache);
DBUG_PRINT("error", ("Cannot start a repair thread"));
sort_info.got_error=1;
} else
sort_info.threads_running++;
}
(void) pthread_attr_destroy(&thr_attr);
/* waiting for all threads to finish */ while (sort_info.threads_running)
mysql_cond_wait(&sort_info.cond, &sort_info.mutex);
mysql_mutex_unlock(&sort_info.mutex);
if ((got_error= _ma_thr_write_keys(sort_param)))
{
param->retry_repair=1; goto err;
}
got_error=1; /* Assume the following may go wrong */
if (_ma_flush_table_files_before_swap(param, info)) goto err;
if (sort_param[0].fix_datafile)
{ /* Appendsomenullstotheendofamemorymappedfile.Destroythe writecache.Themasterthreaddidalreadydetachfromtheshare byremove_io_thread()insort.c:thr_find_all_keys().
*/ if (maria_write_data_suffix(&sort_info,1) ||
end_io_cache(&info->rec_cache)) goto err; if (param->testflag & T_SAFE_REPAIR)
{ /* Don't repair if we loosed more than one row */ if (sort_info.new_info->s->state.state.records+1 < start_records)
{
_ma_check_print_error(param, "Rows lost (Found %lu of %lu); Aborting " "because safe repair was requested",
(ulong) share->state.state.records,
(ulong) start_records);
share->state.state.records=start_records; goto err;
}
}
share->state.state.data_file_length= sort_param->filepos; /* Only whole records */
share->state.version= (ulong) time((time_t*) 0); /* Exchangethedatafiledescriptorofthetable,sothatweusethe newfilefromnowon.
*/
mysql_file_close(info->dfile.file, MYF(0));
info->dfile.file= new_file;
share->pack.header_length=(ulong) new_header_length;
} else
share->state.state.data_file_length=sort_param->max_pos;
if (rep_quick && del+sort_info.dupp != share->state.state.del)
{
_ma_check_print_error(param,"Couldn't fix table with quick recovery: " "Found wrong number of deleted records");
_ma_check_print_error(param,"Run recovery again without -q");
param->retry_repair=1;
param->testflag|=T_RETRY_WITHOUT_QUICK; goto err;
}
if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
my_off_t skr= share->state.state.data_file_length +
((sort_info.org_data_file_type == COMPRESSED_RECORD) ?
MEMMAP_EXTRA_MARGIN : 0); #ifdef USE_RELOC if (sort_info.org_data_file_type == STATIC_RECORD &&
skr < share->base.reloc*share->base.min_pack_length)
skr=share->base.reloc*share->base.min_pack_length; #endif if (skr != sort_info.filelength) if (mysql_file_chsize(info->dfile.file, skr, 0, MYF(0)) > 0)
_ma_check_print_warning(param, "Can't change size of datafile, error: %d",
my_errno);
} if (param->testflag & T_CALC_CHECKSUM)
share->state.state.checksum=param->glob_crc;
if (!share->internal_table &&
mysql_file_chsize(share->kfile.file,
share->state.state.key_file_length, 0, MYF(0)) > 0)
_ma_check_print_warning(param, "Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT))
{ if (start_records != share->state.state.records)
printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
} if (sort_info.dupp)
_ma_check_print_warning(param, "%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0; /* If invoked by external program that uses thr_lock */ if (&share->state.state != info->state)
*info->state= *info->state_start= share->state.state;
err:
_ma_reset_state(info);
/* Destroythewritecache.Themasterthreaddidalreadydetachfrom thesharebyremove_io_thread()oritwasnotyetstarted(ifthe errorhappendbeforecreatingthethread).
*/ if (sort_info.new_info)
{
end_io_cache(&sort_info.new_info->rec_cache);
sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
}
end_io_cache(¶m->read_cache);
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); /* Destroythenewdatacacheincaseofnon-quickrepair.Allslave threadsdideitherdetachfromthesharebyremove_io_thread() alreadyortheywerenotyetstarted(iftheerrorhappendbefore creatingthethreads).
*/ if (!rep_quick && my_b_inited(&new_data_cache))
end_io_cache(&new_data_cache); if (!got_error)
{ /* Replace the actual file with the temporary file */ if (new_file >= 0)
{
mysql_file_close(new_file,MYF(0));
info->dfile.file= new_file= -1; if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
DATA_TMP_EXT, param->backup_time,
MYF((param->testflag & T_BACKUP_DATA ?
MY_REDEL_MAKE_BACKUP : 0) |
sync_dir)) ||
_ma_open_datafile(info,share))
got_error=1;
}
} if (got_error)
{ if (! param->error_printed)
_ma_check_print_error(param,"Got error %d when repairing table with parallel repair",
my_errno);
(void)_ma_flush_table_files_before_swap(param, info); if (new_file >= 0)
{
mysql_file_close(new_file,MYF(0));
mysql_file_delete(key_file_tmp, param->temp_filename, MYF(MY_WME)); if (info->dfile.file == new_file)
info->dfile.file= -1;
}
maria_mark_crashed_on_repair(info);
} elseif (key_map == share->state.key_map)
share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
share->state.changed|= STATE_NOT_SORTED_PAGES; if (!rep_quick)
share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
STATE_NOT_MOVABLE);
/* If caller had disabled logging it's not up to us to re-enable it */ if (reenable_logging)
_ma_reenable_logging_for_table(info, FALSE);
restore_table_state_after_repair(info, &backup_share);
if ((error=sort_get_next_record(sort_param)))
DBUG_RETURN(error); if (info->s->state.state.records == sort_info->max_records)
{
_ma_check_print_error(sort_info->param, "Key %d - Found too many records; Can't continue",
sort_param->key+1);
DBUG_RETURN(1);
} if (_ma_sort_write_record(sort_param))
DBUG_RETURN(1);
if (!sort_param->wordlist)
{ for (;;)
{
free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE)); if ((error=sort_get_next_record(sort_param)))
DBUG_RETURN(error); if ((error= _ma_sort_write_record(sort_param)))
DBUG_RETURN(error); if (!(wptr= _ma_ft_parserecord(info,sort_param->key,sort_param->record,
&sort_param->wordroot)))
if (sort_param->fix_datafile)
{
sort_param->current_filepos= sort_param->filepos; switch (sort_info->new_data_file_type) { case BLOCK_RECORD: if ((sort_param->current_filepos=
(*share->write_record_init)(info, sort_param->record)) ==
HA_OFFSET_ERROR)
{
_ma_check_print_error(param, "%d when writing to datafile", my_errno);
DBUG_RETURN(1);
} /* Pointer to end of file */
sort_param->filepos= share->state.state.data_file_length; break; case STATIC_RECORD: if (my_b_write(&info->rec_cache,sort_param->record,
share->base.pack_reclength))
{
_ma_check_print_error(param,"%d when writing to datafile",my_errno);
DBUG_RETURN(1);
}
sort_param->filepos+=share->base.pack_reclength;
share->state.split++; break; case DYNAMIC_RECORD: if (! info->blobs)
from=sort_param->rec_buff; else
{ /* must be sure that local buffer is big enough */
reclength=share->base.pack_reclength+
_ma_calc_total_blob_length(info,sort_param->record)+
ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
MARIA_DYN_DELETE_BLOCK_HEADER; if (sort_info->buff_length < reclength)
{ if (!(sort_info->buff= my_realloc(PSI_INSTRUMENT_ME, sort_info->buff,
(uint) reclength,
MYF(MY_FREE_ON_ERROR |
MY_ALLOW_ZERO_PTR |
param->malloc_flags))))
DBUG_RETURN(1);
sort_info->buff_length=reclength;
}
from= (uchar *) sort_info->buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER);
} /* We can use info->checksum here as only one thread calls this */
info->cur_row.checksum= (*share->calc_check_checksum)(info,
sort_param->
record); if (!(reclength= _ma_rec_pack(info,from,sort_param->record)))
{
_ma_check_print_error(param,"Got error %d when packing record",
my_errno);
DBUG_RETURN(1);
}
flag=0;
do
{
block_length= reclength + 3 + MY_TEST(reclength >= (65520 - 3)); if (block_length < share->base.min_block_length)
block_length=share->base.min_block_length;
info->update|=HA_STATE_WRITE_AT_END;
block_length=MY_ALIGN(block_length,MARIA_DYN_ALIGN_SIZE); if (block_length > MARIA_MAX_BLOCK_LENGTH)
block_length=MARIA_MAX_BLOCK_LENGTH; if (_ma_write_part_record(info,0L,block_length,
sort_param->filepos+block_length,
&from,&reclength,&flag))
{
_ma_check_print_error(param,"%d when writing to datafile",my_errno);
DBUG_RETURN(1);
}
sort_param->filepos+=block_length;
share->state.split++;
} while (reclength); break; case COMPRESSED_RECORD:
reclength=info->packed_length;
length= _ma_save_pack_length((uint) share->pack.version, block_buff,
reclength); if (share->base.blobs)
length+= _ma_save_pack_length((uint) share->pack.version,
block_buff + length, info->blob_length); if (my_b_write(&info->rec_cache,block_buff,length) ||
my_b_write(&info->rec_cache, sort_param->rec_buff, reclength))
{
_ma_check_print_error(param,"%d when writing to datafile",my_errno);
DBUG_RETURN(1);
}
sort_param->filepos+=reclength+length;
share->state.split++; break; case NO_RECORD:
DBUG_RETURN(1); /* Impossible */
}
} if (sort_param->master)
{
share->state.state.records++; if ((param->testflag & T_WRITE_LOOP) &&
(share->state.state.records % WRITE_COUNT) == 0)
{ char llbuff[22];
printf("%s\r", llstr(share->state.state.records,llbuff));
fflush(stdout);
}
}
DBUG_RETURN(0);
} /* _ma_sort_write_record */
/* Compare two keys from _ma_create_index_by_sort */
if (!ft_buf)
{
sort_param->key_write=sort_key_write; return sort_key_write(sort_param, a);
}
sort_info->ft_buf= ft_buf; goto word_init_ft_buf; /* no need to duplicate the code */
}
get_key_full_length_rdonly(val_off, ft_buf->lastkey);
if (ha_compare_word(sort_param->seg->charset,
a + 1, a_len - 1,
ft_buf->lastkey + 1, val_off - 1) == 0)
{
uchar *p; if (!ft_buf->buf) /* store in second-level tree */
{
ft_buf->count++; return sort_insert_key(sort_param,key_block,
a + a_len, HA_OFFSET_ERROR);
}
/* storing the key in the buffer. */
memcpy (ft_buf->buf, (constchar *)a+a_len, val_len);
ft_buf->buf+=val_len; if (ft_buf->buf < ft_buf->end) return0;
/* converting to two-level tree */
p=ft_buf->lastkey+val_off;
while (key_block->inited)
key_block++;
sort_info->key_block=key_block;
sort_param->keyinfo= &share->ft2_keyinfo;
ft_buf->count=(uint)(ft_buf->buf - p)/val_len;
/* flushing buffer to second-level tree */ for (error=0; !error && p < ft_buf->buf; p+= val_len)
error=sort_insert_key(sort_param,key_block,p,HA_OFFSET_ERROR);
ft_buf->buf=0; return error;
}
/* flushing buffer */ if ((error=_ma_sort_ft_buf_flush(sort_param))) return error;
if (!key_block->inited)
{
key_block->inited=1; if (key_block == sort_info->key_block_end)
{
_ma_check_print_error(param, "To many key-block-levels; " "Try increasing sort_key_blocks");
DBUG_RETURN(1);
}
a_length= share->keypage_header + nod_flag;
key_block->end_pos= anc_buff + share->keypage_header;
bzero(anc_buff, share->keypage_header);
_ma_store_keynr(share, anc_buff, sort_param->keyinfo->key_nr);
lastkey=0; /* No previous key in block */
} else
a_length= _ma_get_page_used(share, anc_buff);
/* Save pointer to previous block */ if (nod_flag)
{
_ma_store_keypage_flag(share, anc_buff, KEYPAGE_FLAG_ISNOD);
_ma_kpointer(info,key_block->end_pos,prev_block);
}
/* Fill block with end-zero and write filled block */
_ma_store_page_used(share, anc_buff, key_block->last_length);
bzero(anc_buff+key_block->last_length,
keyinfo->block_length- key_block->last_length); if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) == HA_OFFSET_ERROR)
DBUG_RETURN(1);
_ma_fast_unlock_key_del(info);
/* If we read the page from the key cache, we have to write it back to it */ if (page_link->changed)
{
MARIA_PAGE page;
pop_dynamic(&info->pinned_pages);
_ma_page_setup(&page, info, keyinfo, filepos, anc_buff); if (_ma_write_keypage(&page, PAGECACHE_LOCK_WRITE_UNLOCK, DFLT_INIT_HITS))
DBUG_RETURN(1);
} else
{ if (write_page(share, share->kfile.file, anc_buff,
keyinfo->block_length, filepos, param->myf_rw))
DBUG_RETURN(1);
}
DBUG_DUMP("buff", anc_buff, _ma_get_page_used(share, anc_buff));
/* Write separator-key to block in next level */ if (sort_insert_key(sort_param,key_block+1,key_block->lastkey,filepos))
DBUG_RETURN(1);
/* clear old block and write new key in it */
key_block->inited=0;
DBUG_RETURN(sort_insert_key(sort_param, key_block,key,prev_block));
} /* sort_insert_key */
/* Delete record when we found a duplicated key */
if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
{
_ma_check_print_error(param, "Quick-recover aborted; Run recovery without switch " "-q or with switch -qq");
DBUG_RETURN(1);
} if (key_info->s->options & HA_OPTION_COMPRESS_RECORD)
{
_ma_check_print_error(param, "Recover aborted; Can't run standard recovery on " "compressed tables with errors in data-file. " "Use 'aria_chk --safe-recover' to fix it");
DBUG_RETURN(1);
}
old_file= row_info->dfile.file; /* This only affects static and dynamic row formats */
row_info->dfile.file= row_info->rec_cache.file; if (flush_io_cache(&row_info->rec_cache))
DBUG_RETURN(1);
key= key_info->lastkey_buff + key_info->s->base.max_key_length; if ((error=(*row_info->s->read_record)(row_info, sort_param->record,
key_info->cur_row.lastpos)) &&
error != HA_ERR_RECORD_DELETED)
{
_ma_check_print_error(param,"Can't read record to be removed");
row_info->dfile.file= old_file;
DBUG_RETURN(1);
}
row_info->cur_row.lastpos= key_info->cur_row.lastpos;
for (i=0 ; i < sort_info->current_key ; i++)
{
MARIA_KEY tmp_key;
(*key_info->s->keyinfo[i].make_key)(key_info, &tmp_key, i, key,
sort_param->record,
key_info->cur_row.lastpos, 0); if (_ma_ck_delete(key_info, &tmp_key))
{
_ma_check_print_error(param, "Can't delete key %d from record to be removed",
i+1);
row_info->dfile.file= old_file;
DBUG_RETURN(1);
}
} if (sort_param->calc_checksum)
param->glob_crc-=(*key_info->s->calc_check_checksum)(key_info,
sort_param->record);
error= (*row_info->s->delete_record)(row_info, sort_param->record); if (error)
_ma_check_print_error(param,"Got error %d when deleting record",
my_errno);
row_info->dfile.file= old_file; /* restore actual value */
row_info->s->state.state.records--;
DBUG_RETURN(error);
} /* sort_delete_record */
/* Fix all pending blocks and flush everything to disk */
key_parts= share.base.all_key_parts; if (!(keysegs=(HA_KEYSEG*) my_alloca(sizeof(HA_KEYSEG)*
(key_parts+share.base.keys))))
{
my_afree(keyinfo);
DBUG_RETURN(1);
} if (!(columndef=(MARIA_COLUMNDEF*)
my_alloca(sizeof(MARIA_COLUMNDEF)*(share.base.fields+1))))
{
my_afree(keyinfo);
my_afree(keysegs);
DBUG_RETURN(1);
} if (!(uniquedef=(MARIA_UNIQUEDEF*)
my_alloca(sizeof(MARIA_UNIQUEDEF)*(share.state.header.uniques+1))))
{
my_afree(columndef);
my_afree(keyinfo);
my_afree(keysegs);
DBUG_RETURN(1);
}
/* Copy the column definitions in their original order */ for (column= share.columndef, end= share.columndef+share.base.fields;
column != end ;
column++)
columndef[column->column_nr]= *column;
/* Change the new key to point at the saved key segments */
memcpy((uchar*) keysegs,(uchar*) share.keyparts,
(size_t) (sizeof(HA_KEYSEG)*(key_parts+share.base.keys+
share.state.header.uniques)));
keyseg=keysegs; for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
{
key->seg=keyseg; for (; keyseg->type ; keyseg++)
{ if (param->language)
keyseg->language=param->language; /* change language */
}
keyseg++; /* Skip end pointer */
}
/* Take into account any bitmap page created above: */
param->filepos= new_info->s->state.state.data_file_length;
/* Use new virtual functions for key generation */
info->s->keypos_to_recpos= new_info->s->keypos_to_recpos;
info->s->recpos_to_keypos= new_info->s->recpos_to_keypos;
DBUG_RETURN(0);
}
for (;;)
{ /* Find next row in current page */ if (likely(record_pos < info->scan.number_of_rows))
{
uint length, offset;
uchar *data, *end_of_data; char llbuff[22];
while (!(offset= uint2korr(info->scan.dir)))
{
info->scan.dir-= DIR_ENTRY_SIZE;
record_pos++; if (info->scan.dir < info->scan.dir_end)
{
_ma_check_print_info(sort_info->param, "Wrong directory on page %s",
llstr(page, llbuff)); goto read_next_page;
}
} /* found row */
info->cur_row.lastpos= info->scan.row_base_page + record_pos;
info->cur_row.nextpos= record_pos + 1;
data= info->scan.page_buff + offset;
length= uint2korr(info->scan.dir + 2);
end_of_data= data + length;
info->scan.dir-= DIR_ENTRY_SIZE; /* Point to previous row */
/* testflaggivesanideaofwhatREPAIRdid(inparticularT_QUICK ornot:didittouchthedatafileornot?).
*/
int8store(log_data + FILEID_STORE_SIZE, param->testflag); /* org_key_map is used when recreating index after a load data infile */
int8store(log_data + FILEID_STORE_SIZE + 8, param->org_key_map);
if (my_errno == HA_ERR_CRASHED)
_ma_check_print_error(param, "Wrong base information on indexpage at page: %s",
llstr(position / block_size, buff)); else
_ma_check_print_error(param, "Can't read indexpage from page: %s, " "error: %d",
llstr(position / block_size, buff), my_errno);
}
staticvoid _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid)
{ char buff[22], buff2[22]; if (!param->not_visible_rows_found++)
{ if (!ma_control_file_inited())
{
_ma_check_print_warning(param, "Found row with transaction id %s but no " "aria_control_file was used or specified. " "The table may be corrupted",
llstr(used_trid, buff));
} else
{
_ma_check_print_error(param, "Found row with transaction id %s when max " "transaction id according to aria_control_file " "is %s",
llstr(used_trid, buff),
llstr(param->max_trid, buff2));
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.