00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "myisam_priv.h"
00044 #include <drizzled/internal/m_string.h>
00045 #include <stdarg.h>
00046 #ifdef HAVE_SYS_VADVISE_H
00047 #include <sys/vadvise.h>
00048 #endif
00049 #ifdef HAVE_SYS_TYPES
00050 #include <sys/types.h>
00051 #endif
00052 #ifdef HAVE_SYS_MMAN_H
00053 #include <sys/mman.h>
00054 #endif
00055 #include <drizzled/util/test.h>
00056 #include <drizzled/error.h>
00057
00058 #include <algorithm>
00059
00060 using namespace std;
00061 using namespace drizzled;
00062 using namespace drizzled::internal;
00063
00064
00065 #define my_off_t2double(A) ((double) (my_off_t) (A))
00066
00067
00068
00069 static int check_k_link(MI_CHECK *param, MI_INFO *info,uint32_t nr);
00070 static int chk_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
00071 my_off_t page, unsigned char *buff, ha_rows *keys,
00072 ha_checksum *key_checksum, uint32_t level);
00073 static uint32_t isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo);
00074 static ha_checksum calc_checksum(ha_rows count);
00075 static int writekeys(MI_SORT_PARAM *sort_param);
00076 static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
00077 my_off_t pagepos, int new_file);
00078 int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
00079 int sort_get_next_record(MI_SORT_PARAM *sort_param);
00080 int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b);
00081 int sort_key_write(MI_SORT_PARAM *sort_param, const void *a);
00082 my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
00083 unsigned char *key);
00084 int sort_insert_key(MI_SORT_PARAM *sort_param,
00085 register SORT_KEY_BLOCKS *key_block,
00086 unsigned char *key, my_off_t prev_block);
00087 int sort_delete_record(MI_SORT_PARAM *sort_param);
00088
00089
00090 static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint32_t blocks,
00091 uint32_t buffer_length);
00092 static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length);
00093 static void set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share);
00094
00095 void myisamchk_init(MI_CHECK *param)
00096 {
00097 memset(param, 0, sizeof(*param));
00098 param->opt_follow_links=1;
00099 param->keys_in_use= ~(uint64_t) 0;
00100 param->search_after_block=HA_OFFSET_ERROR;
00101 param->auto_increment_value= 0;
00102 param->use_buffers=USE_BUFFER_INIT;
00103 param->read_buffer_length=READ_BUFFER_INIT;
00104 param->write_buffer_length=READ_BUFFER_INIT;
00105 param->sort_buffer_length=SORT_BUFFER_INIT;
00106 param->sort_key_blocks=BUFFERS_WHEN_SORTING;
00107 param->tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
00108 param->myf_rw=MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL);
00109 param->start_check_pos=0;
00110 param->max_record_length= INT64_MAX;
00111 param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
00112 param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
00113 }
00114
00115
00116
00117 int chk_status(MI_CHECK *param, register MI_INFO *info)
00118 {
00119 MYISAM_SHARE *share=info->s;
00120
00121 if (mi_is_crashed_on_repair(info))
00122 mi_check_print_warning(param,
00123 "Table is marked as crashed and last repair failed");
00124 else if (mi_is_crashed(info))
00125 mi_check_print_warning(param,
00126 "Table is marked as crashed");
00127 if (share->state.open_count != (uint) (info->s->global_changed ? 1 : 0))
00128 {
00129
00130 uint32_t save=param->warning_printed;
00131 mi_check_print_warning(param,
00132 share->state.open_count==1 ?
00133 "%d client is using or hasn't closed the table properly" :
00134 "%d clients are using or haven't closed the table properly",
00135 share->state.open_count);
00136
00137 if (param->testflag & T_UPDATE_STATE)
00138 param->warning_printed=save;
00139 }
00140 return 0;
00141 }
00142
00143
00144
00145 int chk_del(MI_CHECK *param, register MI_INFO *info, uint32_t test_flag)
00146 {
00147 uint32_t delete_link_length;
00148 my_off_t empty, next_link, old_link= 0;
00149 char buff[22],buff2[22];
00150
00151 param->record_checksum=0;
00152 delete_link_length=((info->s->options & HA_OPTION_PACK_RECORD) ? 20 : info->s->rec_reflength+1);
00153
00154 if (!(test_flag & T_SILENT))
00155 puts("- check record delete-chain");
00156
00157 next_link=info->s->state.dellink;
00158 if (info->state->del == 0)
00159 {
00160 if (test_flag & T_VERBOSE)
00161 {
00162 puts("No recordlinks");
00163 }
00164 }
00165 else
00166 {
00167 if (test_flag & T_VERBOSE)
00168 printf("Recordlinks: ");
00169 empty=0;
00170 ha_rows i= info->state->del;
00171 for (; i > 0 && next_link != HA_OFFSET_ERROR; i--)
00172 {
00173 if (*killed_ptr(param))
00174 return(1);
00175 if (test_flag & T_VERBOSE)
00176 printf(" %9s",llstr(next_link,buff));
00177 if (next_link >= info->state->data_file_length)
00178 goto wrong;
00179 if (my_pread(info->dfile, (unsigned char*) buff,delete_link_length, next_link,MYF(MY_NABP)))
00180 {
00181 if (test_flag & T_VERBOSE) puts("");
00182 mi_check_print_error(param,"Can't read delete-link at filepos: %s",
00183 llstr(next_link,buff));
00184 return(1);
00185 }
00186 if (*buff != '\0')
00187 {
00188 if (test_flag & T_VERBOSE) puts("");
00189 mi_check_print_error(param,"Record at pos: %s is not remove-marked",
00190 llstr(next_link,buff));
00191 goto wrong;
00192 }
00193 if (info->s->options & HA_OPTION_PACK_RECORD)
00194 {
00195 my_off_t prev_link=mi_sizekorr(buff+12);
00196 if (empty && prev_link != old_link)
00197 {
00198 if (test_flag & T_VERBOSE) puts("");
00199 mi_check_print_error(param,"Deleted block at %s doesn't point back at previous delete link",llstr(next_link,buff2));
00200 goto wrong;
00201 }
00202 old_link=next_link;
00203 next_link=mi_sizekorr(buff+4);
00204 empty+=mi_uint3korr(buff+1);
00205 }
00206 else
00207 {
00208 param->record_checksum+=(ha_checksum) next_link;
00209 next_link=_mi_rec_pos(info->s,(unsigned char*) buff+1);
00210 empty+=info->s->base.pack_reclength;
00211 }
00212 }
00213 if (test_flag & T_VERBOSE)
00214 puts("\n");
00215 if (empty != info->state->empty)
00216 {
00217 mi_check_print_warning(param,
00218 "Found %s deleted space in delete link chain. Should be %s",
00219 llstr(empty,buff2),
00220 llstr(info->state->empty,buff));
00221 }
00222 if (next_link != HA_OFFSET_ERROR)
00223 {
00224 mi_check_print_error(param,
00225 "Found more than the expected %s deleted rows in delete link chain",
00226 llstr(info->state->del, buff));
00227 goto wrong;
00228 }
00229 if (i != 0)
00230 {
00231 mi_check_print_error(param, "Found %s deleted rows in delete link chain. Should be %s", llstr(info->state->del - i, buff2), llstr(info->state->del, buff));
00232 goto wrong;
00233 }
00234 }
00235 return 0;
00236
00237 wrong:
00238 param->testflag|=T_RETRY_WITHOUT_QUICK;
00239 if (test_flag & T_VERBOSE) puts("");
00240 mi_check_print_error(param,"record delete-link-chain corrupted");
00241 return 1;
00242 }
00243
00244
00245
00246
00247 static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint32_t nr)
00248 {
00249 my_off_t next_link;
00250 uint32_t block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH;
00251 ha_rows records;
00252 char llbuff[21], llbuff2[21];
00253 unsigned char *buff;
00254
00255 if (param->testflag & T_VERBOSE)
00256 printf("block_size %4u:", block_size);
00257
00258 next_link=info->s->state.key_del[nr];
00259 records= (ha_rows) (info->state->key_file_length / block_size);
00260 while (next_link != HA_OFFSET_ERROR && records > 0)
00261 {
00262 if (*killed_ptr(param))
00263 return(1);
00264 if (param->testflag & T_VERBOSE)
00265 printf("%16s",llstr(next_link,llbuff));
00266
00267
00268 if (next_link + block_size > info->state->key_file_length)
00269 {
00270 mi_check_print_error(param, "Invalid key block position: %s "
00271 "key block size: %u file_length: %s",
00272 llstr(next_link, llbuff), block_size,
00273 llstr(info->state->key_file_length, llbuff2));
00274 return(1);
00275 }
00276
00277
00278 if (next_link & (MI_MIN_KEY_BLOCK_LENGTH - 1))
00279 {
00280 mi_check_print_error(param, "Mis-aligned key block: %s "
00281 "minimum key block length: %u",
00282 llstr(next_link, llbuff), MI_MIN_KEY_BLOCK_LENGTH);
00283 return(1);
00284 }
00285
00286
00287
00288
00289
00290
00291
00292 if (not pread(info->s->kfile, info->buff, MI_MIN_KEY_BLOCK_LENGTH, next_link))
00293 {
00294 mi_check_print_error(param, "key cache read error for block: %s", llstr(next_link,llbuff));
00295 return(1);
00296 }
00297 buff= info->buff;
00298 next_link=mi_sizekorr(buff);
00299 records--;
00300 param->key_file_blocks+=block_size;
00301 }
00302 if (param->testflag & T_VERBOSE)
00303 {
00304 if (next_link != HA_OFFSET_ERROR)
00305 printf("%16s\n",llstr(next_link,llbuff));
00306 else
00307 puts("");
00308 }
00309 return (next_link != HA_OFFSET_ERROR);
00310 }
00311
00312
00313
00314
00315 int chk_size(MI_CHECK *param, register MI_INFO *info)
00316 {
00317 int error=0;
00318 register my_off_t skr,size;
00319 char buff[22],buff2[22];
00320
00321 if (!(param->testflag & T_SILENT)) puts("- check file-size");
00322
00323 size= lseek(info->s->kfile, 0, SEEK_END);
00324 if ((skr=(my_off_t) info->state->key_file_length) != size)
00325 {
00326
00327 if (skr > size && mi_is_any_key_active(info->s->state.key_map))
00328 {
00329 error=1;
00330 mi_check_print_error(param,
00331 "Size of indexfile is: %-8s Should be: %s",
00332 llstr(size,buff), llstr(skr,buff2));
00333 }
00334 else
00335 mi_check_print_warning(param,
00336 "Size of indexfile is: %-8s Should be: %s",
00337 llstr(size,buff), llstr(skr,buff2));
00338 }
00339 if (!(param->testflag & T_VERY_SILENT) &&
00340 ! (info->s->options & HA_OPTION_COMPRESS_RECORD) &&
00341 uint64_t2double(info->state->key_file_length) >
00342 uint64_t2double(info->s->base.margin_key_file_length)*0.9)
00343 mi_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
00344 llstr(info->state->key_file_length,buff),
00345 llstr(info->s->base.max_key_file_length-1,buff));
00346
00347 size=lseek(info->dfile,0L,SEEK_END);
00348 skr=(my_off_t) info->state->data_file_length;
00349 if (info->s->options & HA_OPTION_COMPRESS_RECORD)
00350 skr+= MEMMAP_EXTRA_MARGIN;
00351 #ifdef USE_RELOC
00352 if (info->data_file_type == STATIC_RECORD &&
00353 skr < (my_off_t) info->s->base.reloc*info->s->base.min_pack_length)
00354 skr=(my_off_t) info->s->base.reloc*info->s->base.min_pack_length;
00355 #endif
00356 if (skr != size)
00357 {
00358 info->state->data_file_length=size;
00359 if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
00360 {
00361 error=1;
00362 mi_check_print_error(param,"Size of datafile is: %-9s Should be: %s",
00363 llstr(size,buff), llstr(skr,buff2));
00364 param->testflag|=T_RETRY_WITHOUT_QUICK;
00365 }
00366 else
00367 {
00368 mi_check_print_warning(param,
00369 "Size of datafile is: %-9s Should be: %s",
00370 llstr(size,buff), llstr(skr,buff2));
00371 }
00372 }
00373 if (!(param->testflag & T_VERY_SILENT) &&
00374 !(info->s->options & HA_OPTION_COMPRESS_RECORD) &&
00375 uint64_t2double(info->state->data_file_length) >
00376 (uint64_t2double(info->s->base.max_data_file_length)*0.9))
00377 mi_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
00378 llstr(info->state->data_file_length,buff),
00379 llstr(info->s->base.max_data_file_length-1,buff2));
00380 return(error);
00381 }
00382
00383
00384
00385
00386 int chk_key(MI_CHECK *param, register MI_INFO *info)
00387 {
00388 uint32_t key,found_keys=0,full_text_keys=0,result=0;
00389 ha_rows keys;
00390 ha_checksum old_record_checksum,init_checksum;
00391 my_off_t all_keydata,all_totaldata,key_totlength,length;
00392 ulong *rec_per_key_part;
00393 MYISAM_SHARE *share=info->s;
00394 MI_KEYDEF *keyinfo;
00395 char buff[22],buff2[22];
00396
00397 if (!(param->testflag & T_SILENT))
00398 puts("- check key delete-chain");
00399
00400 param->key_file_blocks=info->s->base.keystart;
00401 for (key=0 ; key < info->s->state.header.max_block_size_index ; key++)
00402 if (check_k_link(param,info,key))
00403 {
00404 if (param->testflag & T_VERBOSE) puts("");
00405 mi_check_print_error(param,"key delete-link-chain corrupted");
00406 return(-1);
00407 }
00408
00409 if (!(param->testflag & T_SILENT)) puts("- check index reference");
00410
00411 all_keydata=all_totaldata=key_totlength=0;
00412 old_record_checksum=0;
00413 init_checksum=param->record_checksum;
00414 if (!(share->options &
00415 (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
00416 old_record_checksum=calc_checksum(info->state->records+info->state->del-1)*
00417 share->base.pack_reclength;
00418 rec_per_key_part= param->rec_per_key_part;
00419 for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
00420 rec_per_key_part+=keyinfo->keysegs, key++, keyinfo++)
00421 {
00422 param->key_crc[key]=0;
00423 if (! mi_is_key_active(share->state.key_map, key))
00424 {
00425
00426 assert(rec_per_key_part >= param->rec_per_key_part);
00427 memcpy(rec_per_key_part,
00428 (share->state.rec_per_key_part +
00429 (rec_per_key_part - param->rec_per_key_part)),
00430 keyinfo->keysegs*sizeof(*rec_per_key_part));
00431 continue;
00432 }
00433 found_keys++;
00434
00435 param->record_checksum=init_checksum;
00436
00437 memset(¶m->unique_count, 0, sizeof(param->unique_count));
00438 memset(¶m->notnull_count, 0, sizeof(param->notnull_count));
00439
00440 if ((!(param->testflag & T_SILENT)))
00441 printf ("- check data record references index: %d\n",key+1);
00442 if (share->state.key_root[key] == HA_OFFSET_ERROR && (info->state->records == 0))
00443 goto do_stat;
00444 if (!_mi_fetch_keypage(info,keyinfo,share->state.key_root[key],
00445 DFLT_INIT_HITS,info->buff,0))
00446 {
00447 mi_check_print_error(param,"Can't read indexpage from filepos: %s",
00448 llstr(share->state.key_root[key],buff));
00449 if (!(param->testflag & T_INFO))
00450 return(-1);
00451 result= UINT32_MAX;
00452 continue;
00453 }
00454 param->key_file_blocks+=keyinfo->block_length;
00455 keys=0;
00456 param->keydata=param->totaldata=0;
00457 param->key_blocks=0;
00458 param->max_level=0;
00459 if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff,
00460 &keys, param->key_crc+key,1))
00461 return(-1);
00462 if(!(0))
00463 {
00464 if (keys != info->state->records)
00465 {
00466 mi_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
00467 llstr(info->state->records,buff2));
00468 if (!(param->testflag & T_INFO))
00469 return(-1);
00470 result= UINT32_MAX;
00471 continue;
00472 }
00473 if (found_keys - full_text_keys == 1 &&
00474 ((share->options &
00475 (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
00476 (param->testflag & T_DONT_CHECK_CHECKSUM)))
00477 old_record_checksum=param->record_checksum;
00478 else if (old_record_checksum != param->record_checksum)
00479 {
00480 if (key)
00481 mi_check_print_error(param,"Key %u doesn't point at same records that key 1",
00482 key+1);
00483 else
00484 mi_check_print_error(param,"Key 1 doesn't point at all records");
00485 if (!(param->testflag & T_INFO))
00486 return(-1);
00487 result= UINT32_MAX;
00488 continue;
00489 }
00490 }
00491 if ((uint) share->base.auto_key -1 == key)
00492 {
00493
00494 uint64_t auto_increment;
00495 info->lastinx=key;
00496 _mi_read_key_record(info, 0L, info->rec_buff);
00497 auto_increment= retrieve_auto_increment(info, info->rec_buff);
00498 if (auto_increment > info->s->state.auto_increment)
00499 {
00500 mi_check_print_warning(param, "Auto-increment value: %s is smaller "
00501 "than max used value: %s",
00502 llstr(info->s->state.auto_increment,buff2),
00503 llstr(auto_increment, buff));
00504 }
00505 if (param->testflag & T_AUTO_INC)
00506 {
00507 set_if_bigger(info->s->state.auto_increment,
00508 auto_increment);
00509 set_if_bigger(info->s->state.auto_increment,
00510 param->auto_increment_value);
00511 }
00512
00513
00514 mi_extra(info,HA_EXTRA_KEYREAD,0);
00515 memset(info->lastkey, 0, keyinfo->seg->length);
00516 if (!mi_rkey(info, info->rec_buff, key, (const unsigned char*) info->lastkey,
00517 (key_part_map)1, HA_READ_KEY_EXACT))
00518 {
00519
00520 uint32_t save=param->warning_printed;
00521 mi_check_print_warning(param, "Found row where the auto_increment "
00522 "column has the value 0");
00523 param->warning_printed=save;
00524 }
00525 mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
00526 }
00527
00528 length=(my_off_t) isam_key_length(info,keyinfo)*keys + param->key_blocks*2;
00529 if (param->testflag & T_INFO && param->totaldata != 0L && keys != 0L)
00530 printf("Key: %2d: Keyblocks used: %3d%% Packed: %4d%% Max levels: %2d\n",
00531 key+1,
00532 (int) (my_off_t2double(param->keydata)*100.0/my_off_t2double(param->totaldata)),
00533 (int) ((my_off_t2double(length) - my_off_t2double(param->keydata))*100.0/
00534 my_off_t2double(length)),
00535 param->max_level);
00536 all_keydata+=param->keydata; all_totaldata+=param->totaldata; key_totlength+=length;
00537
00538 do_stat:
00539 if (param->testflag & T_STATISTICS)
00540 update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
00541 param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
00542 param->notnull_count: NULL,
00543 (uint64_t)info->state->records);
00544 }
00545 if (param->testflag & T_INFO)
00546 {
00547 if (all_totaldata != 0L && found_keys > 0)
00548 printf("Total: Keyblocks used: %3d%% Packed: %4d%%\n\n",
00549 (int) (my_off_t2double(all_keydata)*100.0/
00550 my_off_t2double(all_totaldata)),
00551 (int) ((my_off_t2double(key_totlength) -
00552 my_off_t2double(all_keydata))*100.0/
00553 my_off_t2double(key_totlength)));
00554 else if (all_totaldata != 0L && mi_is_any_key_active(share->state.key_map))
00555 puts("");
00556 }
00557 if (param->key_file_blocks != info->state->key_file_length &&
00558 param->keys_in_use != ~(uint64_t) 0)
00559 mi_check_print_warning(param, "Some data are unreferenced in keyfile");
00560 if (found_keys != full_text_keys)
00561 param->record_checksum=old_record_checksum-init_checksum;
00562 else
00563 param->record_checksum=0;
00564 return(result);
00565 }
00566
00567
00568 static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
00569 my_off_t page, unsigned char *buff, ha_rows *keys,
00570 ha_checksum *key_checksum, uint32_t level)
00571 {
00572 char llbuff[22],llbuff2[22];
00573
00574
00575 if (page + keyinfo->block_length > info->state->key_file_length)
00576 {
00577
00578 my_off_t max_length= lseek(info->s->kfile, 0, SEEK_END);
00579 mi_check_print_error(param, "Invalid key block position: %s "
00580 "key block size: %u file_length: %s",
00581 llstr(page, llbuff), keyinfo->block_length,
00582 llstr(info->state->key_file_length, llbuff2));
00583 if (page + keyinfo->block_length > max_length)
00584 goto err;
00585
00586 info->state->key_file_length= (max_length &
00587 ~ (my_off_t) (keyinfo->block_length - 1));
00588 }
00589
00590
00591 if (page & (MI_MIN_KEY_BLOCK_LENGTH - 1))
00592 {
00593 mi_check_print_error(param, "Mis-aligned key block: %s "
00594 "minimum key block length: %u",
00595 llstr(page, llbuff), MI_MIN_KEY_BLOCK_LENGTH);
00596 goto err;
00597 }
00598
00599 if (!_mi_fetch_keypage(info,keyinfo,page, DFLT_INIT_HITS,buff,0))
00600 {
00601 mi_check_print_error(param,"Can't read key from filepos: %s",
00602 llstr(page,llbuff));
00603 goto err;
00604 }
00605 param->key_file_blocks+=keyinfo->block_length;
00606 if (chk_index(param,info,keyinfo,page,buff,keys,key_checksum,level))
00607 goto err;
00608
00609 return(0);
00610
00611 err:
00612 return(1);
00613 }
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 static
00632 void mi_collect_stats_nonulls_first(HA_KEYSEG *keyseg, uint64_t *notnull,
00633 unsigned char *key)
00634 {
00635 uint32_t first_null, kp;
00636 first_null= ha_find_null(keyseg, key) - keyseg;
00637
00638
00639
00640
00641 for (kp= 0; kp < first_null; kp++)
00642 notnull[kp]++;
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 static
00672 int mi_collect_stats_nonulls_next(HA_KEYSEG *keyseg, uint64_t *notnull,
00673 unsigned char *prev_key, unsigned char *last_key)
00674 {
00675 uint32_t diffs[2];
00676 uint32_t first_null_seg, kp;
00677 HA_KEYSEG *seg;
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY,
00688 SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diffs);
00689 seg= keyseg + diffs[0] - 1;
00690
00691
00692 first_null_seg= ha_find_null(seg, last_key + diffs[1]) - keyseg;
00693 for (kp= 0; kp < first_null_seg; kp++)
00694 notnull[kp]++;
00695
00696
00697
00698
00699
00700
00701 return diffs[0];
00702 }
00703
00704
00705
00706
00707 static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
00708 my_off_t page, unsigned char *buff, ha_rows *keys,
00709 ha_checksum *key_checksum, uint32_t level)
00710 {
00711 int flag;
00712 uint32_t used_length,comp_flag,nod_flag,key_length=0;
00713 unsigned char key[HA_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*endpos;
00714 my_off_t next_page,record;
00715 char llbuff[22];
00716 uint32_t diff_pos[2];
00717
00718 if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
00719 {
00720 mi_check_print_error(param,"Not enough memory for keyblock");
00721 return(-1);
00722 }
00723
00724 if (keyinfo->flag & HA_NOSAME)
00725 comp_flag=SEARCH_FIND | SEARCH_UPDATE;
00726 else
00727 comp_flag=SEARCH_SAME;
00728 nod_flag=mi_test_if_nod(buff);
00729 used_length=mi_getint(buff);
00730 keypos=buff+2+nod_flag;
00731 endpos=buff+used_length;
00732
00733 param->keydata+=used_length; param->totaldata+=keyinfo->block_length;
00734 param->key_blocks++;
00735 if (level > param->max_level)
00736 param->max_level=level;
00737
00738 if (used_length > keyinfo->block_length)
00739 {
00740 mi_check_print_error(param,"Wrong pageinfo at page: %s",
00741 llstr(page,llbuff));
00742 goto err;
00743 }
00744 for ( ;; )
00745 {
00746 if (*killed_ptr(param))
00747 goto err;
00748 memcpy(info->lastkey,key,key_length);
00749 info->lastkey_length=key_length;
00750 if (nod_flag)
00751 {
00752 next_page=_mi_kpos(nod_flag,keypos);
00753 if (chk_index_down(param,info,keyinfo,next_page,
00754 temp_buff,keys,key_checksum,level+1))
00755 goto err;
00756 }
00757 if (keypos >= endpos ||
00758 (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0)
00759 break;
00760 assert(key_length <= sizeof(key));
00761 if (keypos > endpos)
00762 {
00763 mi_check_print_error(param,"Wrong key block length at page: %s",llstr(page,llbuff));
00764 goto err;
00765 }
00766 if ((*keys)++ &&
00767 (flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length,
00768 comp_flag, diff_pos)) >=0)
00769 {
00770 if (comp_flag & SEARCH_FIND && flag == 0)
00771 mi_check_print_error(param,"Found duplicated key at page %s",llstr(page,llbuff));
00772 else
00773 mi_check_print_error(param,"Key in wrong position at page %s",llstr(page,llbuff));
00774 goto err;
00775 }
00776 if (param->testflag & T_STATISTICS)
00777 {
00778 if (*keys != 1L)
00779 {
00780 if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
00781 ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
00782 SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
00783 diff_pos);
00784 else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
00785 {
00786 diff_pos[0]= mi_collect_stats_nonulls_next(keyinfo->seg,
00787 param->notnull_count,
00788 info->lastkey, key);
00789 }
00790 param->unique_count[diff_pos[0]-1]++;
00791 }
00792 else
00793 {
00794 if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
00795 mi_collect_stats_nonulls_first(keyinfo->seg, param->notnull_count,
00796 key);
00797 }
00798 }
00799 (*key_checksum)+= mi_byte_checksum((unsigned char*) key,
00800 key_length- info->s->rec_reflength);
00801 record= _mi_dpos(info,0,key+key_length);
00802 if (record >= info->state->data_file_length)
00803 {
00804 mi_check_print_error(param,"Found key at page %s that points to record outside datafile",llstr(page,llbuff));
00805 goto err;
00806 }
00807 param->record_checksum+=(ha_checksum) record;
00808 }
00809 if (keypos != endpos)
00810 {
00811 mi_check_print_error(param,"Keyblock size at page %s is not correct. Block length: %d key length: %d",
00812 llstr(page,llbuff), used_length, (keypos - buff));
00813 goto err;
00814 }
00815 free(temp_buff);
00816 return(0);
00817 err:
00818 free(temp_buff);
00819 return(1);
00820 }
00821
00822
00823
00824
00825 static ha_checksum calc_checksum(ha_rows count)
00826 {
00827 uint64_t sum,a,b;
00828
00829 sum=0;
00830 a=count; b=count+1;
00831 if (a & 1)
00832 b>>=1;
00833 else
00834 a>>=1;
00835 while (b)
00836 {
00837 if (b & 1)
00838 sum+=a;
00839 a<<=1; b>>=1;
00840 }
00841 return((ha_checksum) sum);
00842 }
00843
00844
00845
00846
00847 static uint32_t isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo)
00848 {
00849 uint32_t length;
00850 HA_KEYSEG *keyseg;
00851
00852 length= info->s->rec_reflength;
00853 for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
00854 length+= keyseg->length;
00855
00856 return(length);
00857 }
00858
00859
00860
00861
00862 int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
00863 {
00864 int error,got_error,flag;
00865 uint key, left_length= 0, b_type;
00866 ha_rows records, del_blocks;
00867 my_off_t used, empty, pos, splits, start_recpos= 0,
00868 del_length, link_used, start_block;
00869 unsigned char *record= NULL, *to= NULL;
00870 char llbuff[22],llbuff2[22],llbuff3[22];
00871 ha_checksum intern_record_checksum;
00872 ha_checksum key_checksum[HA_MAX_POSSIBLE_KEY];
00873 MI_KEYDEF *keyinfo;
00874 MI_BLOCK_INFO block_info;
00875
00876 if (!(param->testflag & T_SILENT))
00877 {
00878 if (extend)
00879 puts("- check records and index references");
00880 else
00881 puts("- check record links");
00882 }
00883
00884 if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
00885 {
00886 mi_check_print_error(param,"Not enough memory for record");
00887 return(-1);
00888 }
00889 records=del_blocks=0;
00890 used=link_used=splits=del_length=0;
00891 intern_record_checksum=param->glob_crc=0;
00892 got_error=error=0;
00893 empty=info->s->pack.header_length;
00894
00895 pos= param->read_cache.tell();
00896 memset(key_checksum, 0, info->s->base.keys * sizeof(key_checksum[0]));
00897 while (pos < info->state->data_file_length)
00898 {
00899 if (*killed_ptr(param))
00900 goto err2;
00901 switch (info->s->data_file_type) {
00902 case STATIC_RECORD:
00903 if (param->read_cache.read(record, info->s->base.pack_reclength))
00904 goto err;
00905 start_recpos=pos;
00906 pos+=info->s->base.pack_reclength;
00907 splits++;
00908 if (*record == '\0')
00909 {
00910 del_blocks++;
00911 del_length+=info->s->base.pack_reclength;
00912 continue;
00913 }
00914 param->glob_crc+= mi_static_checksum(info,record);
00915 used+=info->s->base.pack_reclength;
00916 break;
00917 case DYNAMIC_RECORD:
00918 flag=block_info.second_read=0;
00919 block_info.next_filepos=pos;
00920 do
00921 {
00922 if (_mi_read_cache(¶m->read_cache,(unsigned char*) block_info.header,
00923 (start_block=block_info.next_filepos),
00924 sizeof(block_info.header),
00925 (flag ? 0 : READING_NEXT) | READING_HEADER))
00926 goto err;
00927 if (start_block & (MI_DYN_ALIGN_SIZE-1))
00928 {
00929 mi_check_print_error(param,"Wrong aligned block at %s",
00930 llstr(start_block,llbuff));
00931 goto err2;
00932 }
00933 b_type=_mi_get_block_info(&block_info,-1,start_block);
00934 if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
00935 BLOCK_FATAL_ERROR))
00936 {
00937 if (b_type & BLOCK_SYNC_ERROR)
00938 {
00939 if (flag)
00940 {
00941 mi_check_print_error(param,"Unexpected byte: %d at link: %s",
00942 (int) block_info.header[0],
00943 llstr(start_block,llbuff));
00944 goto err2;
00945 }
00946 pos=block_info.filepos+block_info.block_len;
00947 goto next;
00948 }
00949 if (b_type & BLOCK_DELETED)
00950 {
00951 if (block_info.block_len < info->s->base.min_block_length)
00952 {
00953 mi_check_print_error(param,
00954 "Deleted block with impossible length %lu at %s",
00955 block_info.block_len,llstr(pos,llbuff));
00956 goto err2;
00957 }
00958 if ((block_info.next_filepos != HA_OFFSET_ERROR &&
00959 block_info.next_filepos >= info->state->data_file_length) ||
00960 (block_info.prev_filepos != HA_OFFSET_ERROR &&
00961 block_info.prev_filepos >= info->state->data_file_length))
00962 {
00963 mi_check_print_error(param,"Delete link points outside datafile at %s",
00964 llstr(pos,llbuff));
00965 goto err2;
00966 }
00967 del_blocks++;
00968 del_length+=block_info.block_len;
00969 pos=block_info.filepos+block_info.block_len;
00970 splits++;
00971 goto next;
00972 }
00973 mi_check_print_error(param,"Wrong bytesec: %d-%d-%d at linkstart: %s",
00974 block_info.header[0],block_info.header[1],
00975 block_info.header[2],
00976 llstr(start_block,llbuff));
00977 goto err2;
00978 }
00979 if (info->state->data_file_length < block_info.filepos+
00980 block_info.block_len)
00981 {
00982 mi_check_print_error(param,
00983 "Recordlink that points outside datafile at %s",
00984 llstr(pos,llbuff));
00985 got_error=1;
00986 break;
00987 }
00988 splits++;
00989 if (!flag++)
00990 {
00991 start_recpos=pos;
00992 pos=block_info.filepos+block_info.block_len;
00993 if (block_info.rec_len > (uint) info->s->base.max_pack_length)
00994 {
00995 mi_check_print_error(param,"Found too long record (%lu) at %s",
00996 (ulong) block_info.rec_len,
00997 llstr(start_recpos,llbuff));
00998 got_error=1;
00999 break;
01000 }
01001 if (info->s->base.blobs)
01002 {
01003 if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
01004 &info->rec_buff)))
01005 {
01006 mi_check_print_error(param,
01007 "Not enough memory (%lu) for blob at %s",
01008 (ulong) block_info.rec_len,
01009 llstr(start_recpos,llbuff));
01010 got_error=1;
01011 break;
01012 }
01013 }
01014 else
01015 to= info->rec_buff;
01016 left_length=block_info.rec_len;
01017 }
01018 if (left_length < block_info.data_len)
01019 {
01020 mi_check_print_error(param,"Found too long record (%lu) at %s",
01021 (ulong) block_info.data_len,
01022 llstr(start_recpos,llbuff));
01023 got_error=1;
01024 break;
01025 }
01026 if (_mi_read_cache(¶m->read_cache,(unsigned char*) to,block_info.filepos,
01027 (uint) block_info.data_len,
01028 flag == 1 ? READING_NEXT : 0))
01029 goto err;
01030 to+=block_info.data_len;
01031 link_used+= block_info.filepos-start_block;
01032 used+= block_info.filepos - start_block + block_info.data_len;
01033 empty+=block_info.block_len-block_info.data_len;
01034 left_length-=block_info.data_len;
01035 if (left_length)
01036 {
01037 if (b_type & BLOCK_LAST)
01038 {
01039 mi_check_print_error(param,
01040 "Wrong record length %s of %s at %s",
01041 llstr(block_info.rec_len-left_length,llbuff),
01042 llstr(block_info.rec_len, llbuff2),
01043 llstr(start_recpos,llbuff3));
01044 got_error=1;
01045 break;
01046 }
01047 if (info->state->data_file_length < block_info.next_filepos)
01048 {
01049 mi_check_print_error(param,
01050 "Found next-recordlink that points outside datafile at %s",
01051 llstr(block_info.filepos,llbuff));
01052 got_error=1;
01053 break;
01054 }
01055 }
01056 } while (left_length);
01057 if (! got_error)
01058 {
01059 if (_mi_rec_unpack(info,record,info->rec_buff,block_info.rec_len) ==
01060 MY_FILE_ERROR)
01061 {
01062 mi_check_print_error(param,"Found wrong record at %s",
01063 llstr(start_recpos,llbuff));
01064 got_error=1;
01065 }
01066 else
01067 {
01068 info->checksum=mi_checksum(info,record);
01069 if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE))
01070 {
01071 if (_mi_rec_check(info,record, info->rec_buff,block_info.rec_len,
01072 test(info->s->calc_checksum)))
01073 {
01074 mi_check_print_error(param,"Found wrong packed record at %s",
01075 llstr(start_recpos,llbuff));
01076 got_error=1;
01077 }
01078 }
01079 if (!got_error)
01080 param->glob_crc+= info->checksum;
01081 }
01082 }
01083 else if (!flag)
01084 pos=block_info.filepos+block_info.block_len;
01085 break;
01086 case COMPRESSED_RECORD:
01087 case BLOCK_RECORD:
01088 assert(0);
01089 }
01090 if (! got_error)
01091 {
01092 intern_record_checksum+=(ha_checksum) start_recpos;
01093 records++;
01094 if (param->testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0)
01095 {
01096 printf("%s\r", llstr(records,llbuff)); fflush(stdout);
01097 }
01098
01099
01100
01101 for (key=0,keyinfo= info->s->keyinfo; key < info->s->base.keys;
01102 key++,keyinfo++)
01103 {
01104 if (mi_is_key_active(info->s->state.key_map, key))
01105 {
01106 {
01107 uint32_t key_length=_mi_make_key(info,key,info->lastkey,record,
01108 start_recpos);
01109 if (extend)
01110 {
01111
01112
01113
01114 int search_result=
01115 _mi_search(info,keyinfo,info->lastkey,key_length,
01116 SEARCH_SAME, info->s->state.key_root[key]);
01117 if (search_result)
01118 {
01119 mi_check_print_error(param,"Record at: %10s "
01120 "Can't find key for index: %2d",
01121 llstr(start_recpos,llbuff),key+1);
01122 if (error++ > MAXERR || !(param->testflag & T_VERBOSE))
01123 goto err2;
01124 }
01125 }
01126 else
01127 key_checksum[key]+=mi_byte_checksum((unsigned char*) info->lastkey,
01128 key_length);
01129 }
01130 }
01131 }
01132 }
01133 else
01134 {
01135 got_error=0;
01136 if (error++ > MAXERR || !(param->testflag & T_VERBOSE))
01137 goto err2;
01138 }
01139 next:;
01140 }
01141 if (param->testflag & T_WRITE_LOOP)
01142 {
01143 fputs(" \r",stdout); fflush(stdout);
01144 }
01145 if (records != info->state->records)
01146 {
01147 mi_check_print_error(param,"Record-count is not ok; is %-10s Should be: %s",
01148 llstr(records,llbuff), llstr(info->state->records,llbuff2));
01149 error=1;
01150 }
01151 else if (param->record_checksum &&
01152 param->record_checksum != intern_record_checksum)
01153 {
01154 mi_check_print_error(param,
01155 "Keypointers and record positions doesn't match");
01156 error=1;
01157 }
01158 else if (param->glob_crc != info->state->checksum &&
01159 (info->s->options &
01160 (HA_OPTION_COMPRESS_RECORD)))
01161 {
01162 mi_check_print_warning(param,
01163 "Record checksum is not the same as checksum stored in the index file\n");
01164 error=1;
01165 }
01166 else if (!extend)
01167 {
01168 for (key=0 ; key < info->s->base.keys; key++)
01169 {
01170 if (key_checksum[key] != param->key_crc[key])
01171 {
01172 mi_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records",
01173 key+1);
01174 error=1;
01175 }
01176 }
01177 }
01178
01179 if (del_length != info->state->empty)
01180 {
01181 mi_check_print_warning(param,
01182 "Found %s deleted space. Should be %s",
01183 llstr(del_length,llbuff2),
01184 llstr(info->state->empty,llbuff));
01185 }
01186 if (used+empty+del_length != info->state->data_file_length)
01187 {
01188 mi_check_print_warning(param,
01189 "Found %s record-data and %s unused data and %s deleted-data",
01190 llstr(used,llbuff),llstr(empty,llbuff2),
01191 llstr(del_length,llbuff3));
01192 mi_check_print_warning(param,
01193 "Total %s, Should be: %s",
01194 llstr((used+empty+del_length),llbuff),
01195 llstr(info->state->data_file_length,llbuff2));
01196 }
01197 if (del_blocks != info->state->del)
01198 {
01199 mi_check_print_warning(param,
01200 "Found %10s deleted blocks Should be: %s",
01201 llstr(del_blocks,llbuff),
01202 llstr(info->state->del,llbuff2));
01203 }
01204 if (splits != info->s->state.split)
01205 {
01206 mi_check_print_warning(param,
01207 "Found %10s parts Should be: %s parts",
01208 llstr(splits,llbuff),
01209 llstr(info->s->state.split,llbuff2));
01210 }
01211 if (param->testflag & T_INFO)
01212 {
01213 if (param->warning_printed || param->error_printed)
01214 puts("");
01215 if (used != 0 && ! param->error_printed)
01216 {
01217 printf("Records:%18s M.recordlength:%9lu Packed:%14.0f%%\n",
01218 llstr(records,llbuff), (long)((used-link_used)/records),
01219 (info->s->base.blobs ? 0.0 :
01220 (uint64_t2double((uint64_t) info->s->base.reclength*records)-
01221 my_off_t2double(used))/
01222 uint64_t2double((uint64_t) info->s->base.reclength*records)*100.0));
01223 printf("Recordspace used:%9.0f%% Empty space:%12d%% Blocks/Record: %6.2f\n",
01224 (uint64_t2double(used-link_used)/uint64_t2double(used-link_used+empty)*100.0),
01225 (!records ? 100 : (int) (uint64_t2double(del_length+empty)/
01226 my_off_t2double(used)*100.0)),
01227 uint64_t2double(splits - del_blocks) / records);
01228 }
01229 printf("Record blocks:%12s Delete blocks:%10s\n",
01230 llstr(splits-del_blocks,llbuff),llstr(del_blocks,llbuff2));
01231 printf("Record data: %12s Deleted data: %10s\n",
01232 llstr(used-link_used,llbuff),llstr(del_length,llbuff2));
01233 printf("Lost space: %12s Linkdata: %10s\n",
01234 llstr(empty,llbuff),llstr(link_used,llbuff2));
01235 }
01236 free(mi_get_rec_buff_ptr(info, record));
01237 return (error);
01238 err:
01239 mi_check_print_error(param,"got error: %d when reading datafile at record: %s",errno, llstr(records,llbuff));
01240 err2:
01241 free(mi_get_rec_buff_ptr(info, record));
01242 param->testflag|=T_RETRY_WITHOUT_QUICK;
01243 return(1);
01244 }
01245
01246
01300 static void mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, bool force)
01301 {
01302 MYISAM_SHARE *share= info->s;
01303 MI_STATE_INFO *state= &share->state;
01304 uint32_t i;
01305
01306
01307
01308
01309
01310
01311
01312
01313 if (!force && (param->testflag & T_CREATE_MISSING_KEYS))
01314 {
01315 for (i= 0; i < share->base.keys; i++)
01316 {
01317 if ((state->key_root[i] != HA_OFFSET_ERROR) &&
01318 !mi_is_key_active(state->key_map, i))
01319 {
01320
01321
01322
01323
01324
01325 break;
01326 }
01327 }
01328 if (i >= share->base.keys)
01329 {
01330
01331
01332
01333
01334
01335 return;
01336 }
01337
01338
01339
01340
01341
01342 mi_clear_all_keys_active(state->key_map);
01343 }
01344
01345
01346 for (i= 0; i < share->base.keys; i++)
01347 state->key_root[i]= HA_OFFSET_ERROR;
01348
01349
01350 for (i= 0; i < state->header.max_block_size_index; i++)
01351 state->key_del[i]= HA_OFFSET_ERROR;
01352
01353
01354 info->state->key_file_length= share->base.keystart;
01355 }
01356
01357
01358
01359
01360
01361 int mi_repair(MI_CHECK *param, register MI_INFO *info,
01362 char * name, int rep_quick)
01363 {
01364 int error,got_error;
01365 ha_rows start_records,new_header_length;
01366 my_off_t del;
01367 int new_file;
01368 MYISAM_SHARE *share=info->s;
01369 char llbuff[22],llbuff2[22];
01370 SORT_INFO sort_info;
01371 MI_SORT_PARAM sort_param;
01372
01373 memset(&sort_info, 0, sizeof(sort_info));
01374 memset(&sort_param, 0, sizeof(sort_param));
01375 start_records=info->state->records;
01376 new_header_length=(param->testflag & T_UNPACK) ? 0L :
01377 share->pack.header_length;
01378 got_error=1;
01379 new_file= -1;
01380 sort_param.sort_info=&sort_info;
01381
01382 if (!(param->testflag & T_SILENT))
01383 {
01384 printf("- recovering (with keycache) MyISAM-table '%s'\n",name);
01385 printf("Data records: %s\n", llstr(info->state->records,llbuff));
01386 }
01387 param->testflag|=T_REP;
01388
01389 if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
01390 param->testflag|=T_CALC_CHECKSUM;
01391
01392 if (!param->using_global_keycache)
01393 assert(0);
01394
01395 if (param->read_cache.init_io_cache(info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
01396 {
01397 memset(&info->rec_cache, 0, sizeof(info->rec_cache));
01398 goto err;
01399 }
01400 if (not rep_quick)
01401 {
01402 if (info->rec_cache.init_io_cache(-1, (uint) param->write_buffer_length, WRITE_CACHE, new_header_length, 1, MYF(MY_WME | MY_WAIT_IF_FULL)))
01403 {
01404 goto err;
01405 }
01406 }
01407 info->opt_flag|=WRITE_CACHE_USED;
01408 if (!mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.record) ||
01409 !mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.rec_buff))
01410 {
01411 mi_check_print_error(param, "Not enough memory for extra record");
01412 goto err;
01413 }
01414
01415 if (!rep_quick)
01416 {
01417
01418 if ((new_file=my_create(internal::fn_format(param->temp_filename,
01419 share->data_file_name, "",
01420 DATA_TMP_EXT, 2+4),
01421 0,param->tmpfile_createflag,
01422 MYF(0))) < 0)
01423 {
01424 mi_check_print_error(param,"Can't create new tempfile: '%s'",
01425 param->temp_filename);
01426 goto err;
01427 }
01428 if (new_header_length &&
01429 filecopy(param,new_file,info->dfile,0L,new_header_length,
01430 "datafile-header"))
01431 goto err;
01432 info->s->state.dellink= HA_OFFSET_ERROR;
01433 info->rec_cache.file=new_file;
01434 if (param->testflag & T_UNPACK)
01435 {
01436 share->options&= ~HA_OPTION_COMPRESS_RECORD;
01437 mi_int2store(share->state.header.options,share->options);
01438 }
01439 }
01440 sort_info.info=info;
01441 sort_info.param = param;
01442 sort_param.read_cache=param->read_cache;
01443 sort_param.pos=sort_param.max_pos=share->pack.header_length;
01444 sort_param.filepos=new_header_length;
01445 param->read_cache.end_of_file=sort_info.filelength=
01446 lseek(info->dfile,0L,SEEK_END);
01447 sort_info.dupp=0;
01448 sort_param.fix_datafile= (bool) (! rep_quick);
01449 sort_param.master=1;
01450 sort_info.max_records= ~(ha_rows) 0;
01451
01452 set_data_file_type(&sort_info, share);
01453 del=info->state->del;
01454 info->state->records=info->state->del=share->state.split=0;
01455 info->state->empty=0;
01456 param->glob_crc=0;
01457 if (param->testflag & T_CALC_CHECKSUM)
01458 sort_param.calc_checksum= 1;
01459
01460 info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
01461
01462
01463 if (param->testflag & T_CREATE_MISSING_KEYS)
01464 mi_set_all_keys_active(share->state.key_map, share->base.keys);
01465 mi_drop_all_indexes(param, info, true);
01466
01467 lock_memory(param);
01468
01469
01470 while (!(error=sort_get_next_record(&sort_param)))
01471 {
01472 if (writekeys(&sort_param))
01473 {
01474 if (errno != HA_ERR_FOUND_DUPP_KEY)
01475 goto err;
01476 mi_check_print_info(param,"Duplicate key %2d for record at %10s against new record at %10s",
01477 info->errkey+1,
01478 llstr(sort_param.start_recpos,llbuff),
01479 llstr(info->dupp_key_pos,llbuff2));
01480 if (param->testflag & T_VERBOSE)
01481 {
01482 _mi_make_key(info,(uint) info->errkey,info->lastkey,
01483 sort_param.record,0L);
01484 }
01485 sort_info.dupp++;
01486 if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
01487 {
01488 param->testflag|=T_RETRY_WITHOUT_QUICK;
01489 param->error_printed=1;
01490 goto err;
01491 }
01492 continue;
01493 }
01494 if (sort_write_record(&sort_param))
01495 goto err;
01496 }
01497 if (error > 0 || write_data_suffix(&sort_info, (bool)!rep_quick) ||
01498 info->rec_cache.flush() || param->read_cache.error < 0)
01499 goto err;
01500
01501 if (param->testflag & T_WRITE_LOOP)
01502 {
01503 fputs(" \r",stdout); fflush(stdout);
01504 }
01505 if (ftruncate(share->kfile, info->state->key_file_length))
01506 {
01507 mi_check_print_warning(param,
01508 "Can't change size of indexfile, error: %d",
01509 errno);
01510 goto err;
01511 }
01512
01513 if (rep_quick && del+sort_info.dupp != info->state->del)
01514 {
01515 mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
01516 mi_check_print_error(param,"Run recovery again without -q");
01517 got_error=1;
01518 param->retry_repair=1;
01519 param->testflag|=T_RETRY_WITHOUT_QUICK;
01520 goto err;
01521 }
01522 if (param->testflag & T_SAFE_REPAIR)
01523 {
01524
01525 if (info->state->records+1 < start_records)
01526 {
01527 info->state->records=start_records;
01528 got_error=1;
01529 goto err;
01530 }
01531 }
01532
01533 if (!rep_quick)
01534 {
01535 internal::my_close(info->dfile,MYF(0));
01536 info->dfile=new_file;
01537 info->state->data_file_length=sort_param.filepos;
01538 share->state.version=(ulong) time((time_t*) 0);
01539 }
01540 else
01541 {
01542 info->state->data_file_length=sort_param.max_pos;
01543 }
01544 if (param->testflag & T_CALC_CHECKSUM)
01545 info->state->checksum=param->glob_crc;
01546
01547 if (!(param->testflag & T_SILENT))
01548 {
01549 if (start_records != info->state->records)
01550 printf("Data records: %s\n", llstr(info->state->records,llbuff));
01551 if (sort_info.dupp)
01552 mi_check_print_warning(param,
01553 "%s records have been removed",
01554 llstr(sort_info.dupp,llbuff));
01555 }
01556
01557 got_error=0;
01558
01559 if (&share->state.state != info->state)
01560 memcpy( &share->state.state, info->state, sizeof(*info->state));
01561
01562 err:
01563 if (!got_error)
01564 {
01565
01566 if (new_file >= 0)
01567 {
01568 internal::my_close(new_file,MYF(0));
01569 info->dfile=new_file= -1;
01570 if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
01571 DATA_TMP_EXT, share->base.raid_chunks,
01572 MYF(0)) ||
01573 mi_open_datafile(info,share,-1))
01574 got_error=1;
01575 }
01576 }
01577 if (got_error)
01578 {
01579 if (! param->error_printed)
01580 mi_check_print_error(param,"%d for record at pos %s",errno,
01581 llstr(sort_param.start_recpos,llbuff));
01582 if (new_file >= 0)
01583 {
01584 internal::my_close(new_file,MYF(0));
01585 my_delete(param->temp_filename, MYF(MY_WME));
01586 info->rec_cache.file=-1;
01587 }
01588 mi_mark_crashed_on_repair(info);
01589 }
01590
01591 void * rec_buff_ptr= NULL;
01592 rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.rec_buff);
01593 free(rec_buff_ptr);
01594 rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
01595 free(rec_buff_ptr);
01596 rec_buff_ptr= NULL;
01597
01598 free(sort_info.buff);
01599 param->read_cache.end_io_cache();
01600 info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
01601 info->rec_cache.end_io_cache();
01602 if (not got_error && param->testflag & T_UNPACK)
01603 {
01604 share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
01605 share->pack.header_length=0;
01606 share->data_file_type=sort_info.new_data_file_type;
01607 }
01608 share->state.changed|= (STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES |
01609 STATE_NOT_ANALYZED);
01610 return(got_error);
01611 }
01612
01613
01614
01615
01616 static int writekeys(MI_SORT_PARAM *sort_param)
01617 {
01618 register uint32_t i;
01619 unsigned char *key;
01620 MI_INFO *info= sort_param->sort_info->info;
01621 unsigned char *buff= sort_param->record;
01622 my_off_t filepos= sort_param->filepos;
01623
01624 key=info->lastkey+info->s->base.max_key_length;
01625 for (i=0 ; i < info->s->base.keys ; i++)
01626 {
01627 if (mi_is_key_active(info->s->state.key_map, i))
01628 {
01629 {
01630 uint32_t key_length=_mi_make_key(info,i,key,buff,filepos);
01631 if (_mi_ck_write(info,i,key,key_length))
01632 goto err;
01633 }
01634 }
01635 }
01636 return(0);
01637
01638 err:
01639 if (errno == HA_ERR_FOUND_DUPP_KEY)
01640 {
01641 info->errkey=(int) i;
01642 while ( i-- > 0 )
01643 {
01644 if (mi_is_key_active(info->s->state.key_map, i))
01645 {
01646 {
01647 uint32_t key_length=_mi_make_key(info,i,key,buff,filepos);
01648 if (_mi_ck_delete(info,i,key,key_length))
01649 break;
01650 }
01651 }
01652 }
01653 }
01654
01655 if (sort_param->calc_checksum)
01656 sort_param->sort_info->param->glob_crc-= info->checksum;
01657 return(-1);
01658 }
01659
01660
01661
01662
01663 int movepoint(register MI_INFO *info, unsigned char *record, my_off_t oldpos,
01664 my_off_t newpos, uint32_t prot_key)
01665 {
01666 register uint32_t i;
01667 unsigned char *key;
01668 uint32_t key_length;
01669
01670 key=info->lastkey+info->s->base.max_key_length;
01671 for (i=0 ; i < info->s->base.keys; i++)
01672 {
01673 if (i != prot_key && mi_is_key_active(info->s->state.key_map, i))
01674 {
01675 key_length=_mi_make_key(info,i,key,record,oldpos);
01676 if (info->s->keyinfo[i].flag & HA_NOSAME)
01677 {
01678 uint32_t nod_flag;
01679 MI_KEYDEF *keyinfo;
01680 keyinfo=info->s->keyinfo+i;
01681 if (_mi_search(info,keyinfo,key,USE_WHOLE_KEY,
01682 (uint) (SEARCH_SAME | SEARCH_SAVE_BUFF),
01683 info->s->state.key_root[i]))
01684 return(-1);
01685 nod_flag=mi_test_if_nod(info->buff);
01686 _mi_dpointer(info,info->int_keypos-nod_flag-
01687 info->s->rec_reflength,newpos);
01688 if (_mi_write_keypage(info,keyinfo,info->last_keypage,
01689 DFLT_INIT_HITS,info->buff))
01690 return(-1);
01691 }
01692 else
01693 {
01694 if (_mi_ck_delete(info,i,key,key_length))
01695 return(-1);
01696 key_length=_mi_make_key(info,i,key,record,newpos);
01697 if (_mi_ck_write(info,i,key,key_length))
01698 return(-1);
01699 }
01700 }
01701 }
01702 return(0);
01703 }
01704
01705
01706
01707
01708 void lock_memory(MI_CHECK *)
01709 {
01710 }
01711
01712
01713
01714
01715 int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
01716 {
01717 register uint32_t key;
01718 register MI_KEYDEF *keyinfo;
01719 int new_file;
01720 my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
01721 uint32_t r_locks,w_locks;
01722 int old_lock;
01723 MYISAM_SHARE *share=info->s;
01724 MI_STATE_INFO old_state;
01725
01726
01727 for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
01728 key++,keyinfo++)
01729
01730 if (!(param->testflag & T_SILENT))
01731 printf("- Sorting index for MyISAM-table '%s'\n",name);
01732
01733
01734 internal::fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32);
01735 if ((new_file=my_create(internal::fn_format(param->temp_filename,param->temp_filename,
01736 "", INDEX_TMP_EXT,2+4),
01737 0,param->tmpfile_createflag,MYF(0))) <= 0)
01738 {
01739 mi_check_print_error(param,"Can't create new tempfile: '%s'",
01740 param->temp_filename);
01741 return(-1);
01742 }
01743 if (filecopy(param, new_file,share->kfile,0L,
01744 (ulong) share->base.keystart, "headerblock"))
01745 goto err;
01746
01747 param->new_file_pos=share->base.keystart;
01748 for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
01749 key++,keyinfo++)
01750 {
01751 if (! mi_is_key_active(info->s->state.key_map, key))
01752 continue;
01753
01754 if (share->state.key_root[key] != HA_OFFSET_ERROR)
01755 {
01756 index_pos[key]=param->new_file_pos;
01757 if (sort_one_index(param,info,keyinfo,share->state.key_root[key],
01758 new_file))
01759 goto err;
01760 }
01761 else
01762 index_pos[key]= HA_OFFSET_ERROR;
01763 }
01764
01765 share->state.version=(ulong) time(NULL);
01766 old_state= share->state;
01767 r_locks= share->r_locks;
01768 w_locks= share->w_locks;
01769 old_lock= info->lock_type;
01770
01771
01772 share->r_locks= share->w_locks= share->tot_locks= 0;
01773 (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
01774 internal::my_close(share->kfile,MYF(MY_WME));
01775 share->kfile = -1;
01776 internal::my_close(new_file,MYF(MY_WME));
01777 if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
01778 MYF(0)) ||
01779 mi_open_keyfile(share))
01780 goto err2;
01781 info->lock_type= F_UNLCK;
01782 _mi_readinfo(info,F_WRLCK,0);
01783 info->lock_type= old_lock;
01784 share->r_locks= r_locks;
01785 share->w_locks= w_locks;
01786 share->tot_locks= r_locks+w_locks;
01787 share->state= old_state;
01788
01789 info->state->key_file_length=param->new_file_pos;
01790 info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
01791 for (key=0 ; key < info->s->base.keys ; key++)
01792 info->s->state.key_root[key]=index_pos[key];
01793 for (key=0 ; key < info->s->state.header.max_block_size_index ; key++)
01794 info->s->state.key_del[key]= HA_OFFSET_ERROR;
01795
01796 info->s->state.changed&= ~STATE_NOT_SORTED_PAGES;
01797 return(0);
01798
01799 err:
01800 internal::my_close(new_file,MYF(MY_WME));
01801 err2:
01802 my_delete(param->temp_filename,MYF(MY_WME));
01803 return(-1);
01804 }
01805
01806
01807
01808
01809 static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
01810 my_off_t pagepos, int new_file)
01811 {
01812 uint32_t length,nod_flag,used_length, key_length;
01813 unsigned char *buff,*keypos,*endpos;
01814 unsigned char key[HA_MAX_POSSIBLE_KEY_BUFF];
01815 my_off_t new_page_pos,next_page;
01816 char llbuff[22];
01817
01818 new_page_pos=param->new_file_pos;
01819 param->new_file_pos+=keyinfo->block_length;
01820
01821 if (!(buff=(unsigned char*) malloc(keyinfo->block_length)))
01822 {
01823 mi_check_print_error(param,"Not enough memory for key block");
01824 return(-1);
01825 }
01826 if (!_mi_fetch_keypage(info,keyinfo,pagepos,DFLT_INIT_HITS,buff,0))
01827 {
01828 mi_check_print_error(param,"Can't read key block from filepos: %s",
01829 llstr(pagepos,llbuff));
01830 goto err;
01831 }
01832 if ((nod_flag=mi_test_if_nod(buff)))
01833 {
01834 used_length=mi_getint(buff);
01835 keypos=buff+2+nod_flag;
01836 endpos=buff+used_length;
01837 for ( ;; )
01838 {
01839 if (nod_flag)
01840 {
01841 next_page=_mi_kpos(nod_flag,keypos);
01842 _mi_kpointer(info,keypos-nod_flag,param->new_file_pos);
01843 if (sort_one_index(param,info,keyinfo,next_page,new_file))
01844 {
01845 goto err;
01846 }
01847 }
01848 if (keypos >= endpos ||
01849 (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0)
01850 break;
01851 assert(keypos <= endpos);
01852 }
01853 }
01854
01855
01856 length=mi_getint(buff);
01857 memset(buff+length, 0, keyinfo->block_length-length);
01858 if (my_pwrite(new_file,(unsigned char*) buff,(uint) keyinfo->block_length,
01859 new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
01860 {
01861 mi_check_print_error(param,"Can't write indexblock, error: %d",errno);
01862 goto err;
01863 }
01864 free(buff);
01865 return(0);
01866 err:
01867 free(buff);
01868 return(1);
01869 }
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881 int change_to_newfile(const char * filename, const char * old_ext,
01882 const char * new_ext,
01883 uint32_t raid_chunks,
01884 myf MyFlags)
01885 {
01886 (void)raid_chunks;
01887 char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
01888
01889 (void) internal::fn_format(old_filename,filename,"",old_ext,2+4+32);
01890 return my_redel(old_filename,
01891 internal::fn_format(new_filename,old_filename,"",new_ext,2+4),
01892 MYF(MY_WME | MY_LINK_WARNING | MyFlags));
01893 }
01894
01895
01896
01897
01898
01899 int filecopy(MI_CHECK *param, int to,int from,my_off_t start,
01900 my_off_t length, const char *type)
01901 {
01902 char tmp_buff[IO_SIZE],*buff;
01903 ulong buff_length;
01904
01905 buff_length=(ulong) min(param->write_buffer_length, (size_t)length);
01906 if (!(buff=(char *)malloc(buff_length)))
01907 {
01908 buff=tmp_buff; buff_length=IO_SIZE;
01909 }
01910
01911 lseek(from,start,SEEK_SET);
01912 while (length > buff_length)
01913 {
01914 if (my_read(from,(unsigned char*) buff,buff_length,MYF(MY_NABP)) ||
01915 my_write(to,(unsigned char*) buff,buff_length,param->myf_rw))
01916 goto err;
01917 length-= buff_length;
01918 }
01919 if (my_read(from,(unsigned char*) buff,(uint) length,MYF(MY_NABP)) ||
01920 my_write(to,(unsigned char*) buff,(uint) length,param->myf_rw))
01921 goto err;
01922 if (buff != tmp_buff)
01923 free(buff);
01924 return(0);
01925 err:
01926 if (buff != tmp_buff)
01927 free(buff);
01928 mi_check_print_error(param,"Can't copy %s to tempfile, error %d",
01929 type,errno);
01930 return(1);
01931 }
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949 int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
01950 const char * name, int rep_quick)
01951 {
01952 int got_error;
01953 uint32_t i;
01954 ulong length;
01955 ha_rows start_records;
01956 my_off_t new_header_length,del;
01957 int new_file;
01958 MI_SORT_PARAM sort_param;
01959 MYISAM_SHARE *share=info->s;
01960 HA_KEYSEG *keyseg;
01961 ulong *rec_per_key_part;
01962 char llbuff[22];
01963 SORT_INFO sort_info;
01964 uint64_t key_map= 0;
01965
01966 start_records=info->state->records;
01967 got_error=1;
01968 new_file= -1;
01969 new_header_length=(param->testflag & T_UNPACK) ? 0 :
01970 share->pack.header_length;
01971 if (!(param->testflag & T_SILENT))
01972 {
01973 printf("- recovering (with sort) MyISAM-table '%s'\n",name);
01974 printf("Data records: %s\n", llstr(start_records,llbuff));
01975 }
01976 param->testflag|=T_REP;
01977
01978 if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
01979 param->testflag|=T_CALC_CHECKSUM;
01980
01981 memset(&sort_info, 0, sizeof(sort_info));
01982 memset(&sort_param, 0, sizeof(sort_param));
01983 if (!(sort_info.key_block=
01984 alloc_key_blocks(param, (uint) param->sort_key_blocks, share->base.max_key_block_length))
01985 || param->read_cache.init_io_cache(info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME))
01986 || (! rep_quick && info->rec_cache.init_io_cache(info->dfile, (uint) param->write_buffer_length, WRITE_CACHE,new_header_length,1, MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)))
01987 {
01988 goto err;
01989 }
01990 sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
01991 info->opt_flag|=WRITE_CACHE_USED;
01992 info->rec_cache.file=info->dfile;
01993
01994 if (!mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.record) ||
01995 !mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.rec_buff))
01996 {
01997 mi_check_print_error(param, "Not enough memory for extra record");
01998 goto err;
01999 }
02000 if (!rep_quick)
02001 {
02002
02003 if ((new_file=my_create(internal::fn_format(param->temp_filename,
02004 share->data_file_name, "",
02005 DATA_TMP_EXT, 2+4),
02006 0,param->tmpfile_createflag,
02007 MYF(0))) < 0)
02008 {
02009 mi_check_print_error(param,"Can't create new tempfile: '%s'",
02010 param->temp_filename);
02011 goto err;
02012 }
02013 if (new_header_length &&
02014 filecopy(param, new_file,info->dfile,0L,new_header_length,
02015 "datafile-header"))
02016 goto err;
02017 if (param->testflag & T_UNPACK)
02018 {
02019 share->options&= ~HA_OPTION_COMPRESS_RECORD;
02020 mi_int2store(share->state.header.options,share->options);
02021 }
02022 share->state.dellink= HA_OFFSET_ERROR;
02023 info->rec_cache.file=new_file;
02024 }
02025
02026 info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
02027
02028
02029 mi_drop_all_indexes(param, info, false);
02030 key_map= share->state.key_map;
02031 if (param->testflag & T_CREATE_MISSING_KEYS)
02032 {
02033
02034 key_map= ~key_map;
02035 }
02036
02037 sort_info.info=info;
02038 sort_info.param = param;
02039
02040 set_data_file_type(&sort_info, share);
02041 sort_param.filepos=new_header_length;
02042 sort_info.dupp=0;
02043 sort_info.buff=0;
02044 param->read_cache.end_of_file=sort_info.filelength=
02045 lseek(param->read_cache.file,0L,SEEK_END);
02046
02047 sort_param.wordlist=NULL;
02048
02049 if (share->data_file_type == DYNAMIC_RECORD)
02050 length=max(share->base.min_pack_length+1,share->base.min_block_length);
02051 else if (share->data_file_type == COMPRESSED_RECORD)
02052 length=share->base.min_block_length;
02053 else
02054 length=share->base.pack_reclength;
02055 sort_info.max_records=
02056 ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records :
02057 (ha_rows) (sort_info.filelength/length+1));
02058 sort_param.key_cmp=sort_key_cmp;
02059 sort_param.lock_in_memory=lock_memory;
02060 sort_param.sort_info=&sort_info;
02061 sort_param.fix_datafile= (bool) (! rep_quick);
02062 sort_param.master =1;
02063
02064 del=info->state->del;
02065 param->glob_crc=0;
02066 if (param->testflag & T_CALC_CHECKSUM)
02067 sort_param.calc_checksum= 1;
02068
02069 rec_per_key_part= param->rec_per_key_part;
02070 for (sort_param.key=0 ; sort_param.key < share->base.keys ;
02071 rec_per_key_part+=sort_param.keyinfo->keysegs, sort_param.key++)
02072 {
02073 sort_param.read_cache=param->read_cache;
02074 sort_param.keyinfo=share->keyinfo+sort_param.key;
02075 sort_param.seg=sort_param.keyinfo->seg;
02076
02077
02078
02079
02080 if (! mi_is_key_active(key_map, sort_param.key))
02081 {
02082
02083 assert(rec_per_key_part >= param->rec_per_key_part);
02084 memcpy(rec_per_key_part,
02085 (share->state.rec_per_key_part +
02086 (rec_per_key_part - param->rec_per_key_part)),
02087 sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
02088 continue;
02089 }
02090
02091 if ((!(param->testflag & T_SILENT)))
02092 printf ("- Fixing index %d\n",sort_param.key+1);
02093 sort_param.max_pos=sort_param.pos=share->pack.header_length;
02094 keyseg=sort_param.seg;
02095 memset(sort_param.unique, 0, sizeof(sort_param.unique));
02096 sort_param.key_length=share->rec_reflength;
02097 for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++)
02098 {
02099 sort_param.key_length+=keyseg[i].length;
02100 if (keyseg[i].flag & HA_SPACE_PACK)
02101 sort_param.key_length+=get_pack_length(keyseg[i].length);
02102 if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
02103 sort_param.key_length+=2 + test(keyseg[i].length >= 127);
02104 if (keyseg[i].flag & HA_NULL_PART)
02105 sort_param.key_length++;
02106 }
02107 info->state->records=info->state->del=share->state.split=0;
02108 info->state->empty=0;
02109
02110 {
02111 sort_param.key_read=sort_key_read;
02112 sort_param.key_write=sort_key_write;
02113 }
02114
02115 if (_create_index_by_sort(&sort_param,
02116 (bool) (!(param->testflag & T_VERBOSE)),
02117 (uint) param->sort_buffer_length))
02118 {
02119 param->retry_repair=1;
02120 goto err;
02121 }
02122
02123 sort_param.calc_checksum= 0;
02124 sort_param.wordroot.free_root(MYF(0));
02125
02126
02127 sort_info.max_records= (ha_rows) info->state->records;
02128
02129 if (param->testflag & T_STATISTICS)
02130 update_key_parts(sort_param.keyinfo, rec_per_key_part, sort_param.unique,
02131 param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
02132 sort_param.notnull: NULL,
02133 (uint64_t) info->state->records);
02134
02135 mi_set_key_active(share->state.key_map, sort_param.key);
02136
02137 if (sort_param.fix_datafile)
02138 {
02139 param->read_cache.end_of_file=sort_param.filepos;
02140 if (write_data_suffix(&sort_info, 1) || info->rec_cache.end_io_cache())
02141 {
02142 goto err;
02143 }
02144 if (param->testflag & T_SAFE_REPAIR)
02145 {
02146
02147 if (info->state->records+1 < start_records)
02148 {
02149 info->state->records=start_records;
02150 goto err;
02151 }
02152 }
02153 share->state.state.data_file_length = info->state->data_file_length=
02154 sort_param.filepos;
02155
02156 share->state.version=(ulong) time((time_t*) 0);
02157 internal::my_close(info->dfile,MYF(0));
02158 info->dfile=new_file;
02159 share->data_file_type=sort_info.new_data_file_type;
02160 share->pack.header_length=(ulong) new_header_length;
02161 sort_param.fix_datafile=0;
02162 }
02163 else
02164 info->state->data_file_length=sort_param.max_pos;
02165
02166 param->read_cache.file=info->dfile;
02167 param->read_cache.reinit_io_cache(READ_CACHE,share->pack.header_length, 1,1);
02168 }
02169
02170 if (param->testflag & T_WRITE_LOOP)
02171 {
02172 fputs(" \r",stdout); fflush(stdout);
02173 }
02174
02175 if (rep_quick && del+sort_info.dupp != info->state->del)
02176 {
02177 mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
02178 mi_check_print_error(param,"Run recovery again without -q");
02179 got_error=1;
02180 param->retry_repair=1;
02181 param->testflag|=T_RETRY_WITHOUT_QUICK;
02182 goto err;
02183 }
02184
02185 if (rep_quick & T_FORCE_UNIQUENESS)
02186 {
02187 my_off_t skr=info->state->data_file_length+
02188 (share->options & HA_OPTION_COMPRESS_RECORD ?
02189 MEMMAP_EXTRA_MARGIN : 0);
02190 #ifdef USE_RELOC
02191 if (share->data_file_type == STATIC_RECORD &&
02192 skr < share->base.reloc*share->base.min_pack_length)
02193 skr=share->base.reloc*share->base.min_pack_length;
02194 #endif
02195 if (skr != sort_info.filelength && !info->s->base.raid_type)
02196 if (ftruncate(info->dfile, skr))
02197 mi_check_print_warning(param,
02198 "Can't change size of datafile, error: %d",
02199 errno);
02200 }
02201 if (param->testflag & T_CALC_CHECKSUM)
02202 info->state->checksum=param->glob_crc;
02203
02204 if (ftruncate(share->kfile, info->state->key_file_length))
02205 mi_check_print_warning(param,
02206 "Can't change size of indexfile, error: %d",
02207 errno);
02208
02209 if (!(param->testflag & T_SILENT))
02210 {
02211 if (start_records != info->state->records)
02212 printf("Data records: %s\n", llstr(info->state->records,llbuff));
02213 if (sort_info.dupp)
02214 mi_check_print_warning(param,
02215 "%s records have been removed",
02216 llstr(sort_info.dupp,llbuff));
02217 }
02218 got_error=0;
02219
02220 if (&share->state.state != info->state)
02221 memcpy( &share->state.state, info->state, sizeof(*info->state));
02222
02223 err:
02224 info->rec_cache.end_io_cache();
02225 if (!got_error)
02226 {
02227
02228 if (new_file >= 0)
02229 {
02230 internal::my_close(new_file,MYF(0));
02231 info->dfile=new_file= -1;
02232 if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
02233 DATA_TMP_EXT, share->base.raid_chunks,
02234 MYF(0)) ||
02235 mi_open_datafile(info,share,-1))
02236 got_error=1;
02237 }
02238 }
02239 if (got_error)
02240 {
02241 if (! param->error_printed)
02242 mi_check_print_error(param,"%d when fixing table",errno);
02243 if (new_file >= 0)
02244 {
02245 internal::my_close(new_file,MYF(0));
02246 my_delete(param->temp_filename, MYF(MY_WME));
02247 if (info->dfile == new_file)
02248 info->dfile= -1;
02249 }
02250 mi_mark_crashed_on_repair(info);
02251 }
02252 else if (key_map == share->state.key_map)
02253 share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
02254 share->state.changed|=STATE_NOT_SORTED_PAGES;
02255
02256 void * rec_buff_ptr= NULL;
02257 rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.rec_buff);
02258 free(rec_buff_ptr);
02259 rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
02260 free(rec_buff_ptr);
02261 rec_buff_ptr= NULL;
02262
02263 free((unsigned char*) sort_info.key_block);
02264 free(sort_info.buff);
02265 param->read_cache.end_io_cache();
02266 info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
02267 if (!got_error && (param->testflag & T_UNPACK))
02268 {
02269 share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
02270 share->pack.header_length=0;
02271 }
02272 return(got_error);
02273 }
02274
02275
02276
02277 int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
02278 {
02279 int error;
02280 SORT_INFO *sort_info=sort_param->sort_info;
02281 MI_INFO *info=sort_info->info;
02282
02283 if ((error=sort_get_next_record(sort_param)))
02284 return(error);
02285 if (info->state->records == sort_info->max_records)
02286 {
02287 mi_check_print_error(sort_info->param,
02288 "Key %d - Found too many records; Can't continue",
02289 sort_param->key+1);
02290 return(1);
02291 }
02292 sort_param->real_key_length=
02293 (info->s->rec_reflength+
02294 _mi_make_key(info, sort_param->key, (unsigned char*) key,
02295 sort_param->record, sort_param->filepos));
02296 #ifdef HAVE_VALGRIND
02297 memset((unsigned char *)key+sort_param->real_key_length, 0,
02298 (sort_param->key_length-sort_param->real_key_length));
02299 #endif
02300 return(sort_write_record(sort_param));
02301 }
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335 int sort_get_next_record(MI_SORT_PARAM *sort_param)
02336 {
02337 int searching;
02338 int parallel_flag;
02339 uint32_t found_record,b_type,left_length;
02340 my_off_t pos;
02341 unsigned char *to= NULL;
02342 MI_BLOCK_INFO block_info;
02343 SORT_INFO *sort_info=sort_param->sort_info;
02344 MI_CHECK *param=sort_info->param;
02345 MI_INFO *info=sort_info->info;
02346 MYISAM_SHARE *share=info->s;
02347 char llbuff[22],llbuff2[22];
02348
02349 if (*killed_ptr(param))
02350 return(1);
02351
02352 switch (share->data_file_type) {
02353 case STATIC_RECORD:
02354 for (;;)
02355 {
02356 if (sort_param->read_cache.read(sort_param->record, share->base.pack_reclength))
02357 {
02358 if (sort_param->read_cache.error)
02359 param->out_flag |= O_DATA_LOST;
02360 param->retry_repair=1;
02361 param->testflag|=T_RETRY_WITHOUT_QUICK;
02362 return(-1);
02363 }
02364 sort_param->start_recpos=sort_param->pos;
02365 if (!sort_param->fix_datafile)
02366 {
02367 sort_param->filepos=sort_param->pos;
02368 if (sort_param->master)
02369 share->state.split++;
02370 }
02371 sort_param->max_pos=(sort_param->pos+=share->base.pack_reclength);
02372 if (*sort_param->record)
02373 {
02374 if (sort_param->calc_checksum)
02375 param->glob_crc+= (info->checksum=
02376 mi_static_checksum(info,sort_param->record));
02377 return(0);
02378 }
02379 if (!sort_param->fix_datafile && sort_param->master)
02380 {
02381 info->state->del++;
02382 info->state->empty+=share->base.pack_reclength;
02383 }
02384 }
02385 case DYNAMIC_RECORD:
02386 pos= sort_param->pos;
02387 searching= (sort_param->fix_datafile && (param->testflag & T_EXTEND));
02388 parallel_flag= (sort_param->read_cache.file < 0) ? READING_NEXT : 0;
02389 for (;;)
02390 {
02391 found_record=block_info.second_read= 0;
02392 left_length=1;
02393 if (searching)
02394 {
02395 pos=MY_ALIGN(pos,MI_DYN_ALIGN_SIZE);
02396 param->testflag|=T_RETRY_WITHOUT_QUICK;
02397 sort_param->start_recpos=pos;
02398 }
02399 do
02400 {
02401 if (pos > sort_param->max_pos)
02402 sort_param->max_pos=pos;
02403 if (pos & (MI_DYN_ALIGN_SIZE-1))
02404 {
02405 if ((param->testflag & T_VERBOSE) || searching == 0)
02406 mi_check_print_info(param,"Wrong aligned block at %s",
02407 llstr(pos,llbuff));
02408 if (searching)
02409 goto try_next;
02410 }
02411 if (found_record && pos == param->search_after_block)
02412 mi_check_print_info(param,"Block: %s used by record at %s",
02413 llstr(param->search_after_block,llbuff),
02414 llstr(sort_param->start_recpos,llbuff2));
02415 if (_mi_read_cache(&sort_param->read_cache,
02416 (unsigned char*) block_info.header,pos,
02417 MI_BLOCK_INFO_HEADER_LENGTH,
02418 (! found_record ? READING_NEXT : 0) |
02419 parallel_flag | READING_HEADER))
02420 {
02421 if (found_record)
02422 {
02423 mi_check_print_info(param,
02424 "Can't read whole record at %s (errno: %d)",
02425 llstr(sort_param->start_recpos,llbuff),errno);
02426 goto try_next;
02427 }
02428 return(-1);
02429 }
02430 if (searching && ! sort_param->fix_datafile)
02431 {
02432 param->error_printed=1;
02433 param->retry_repair=1;
02434 param->testflag|=T_RETRY_WITHOUT_QUICK;
02435 return(1);
02436 }
02437 b_type=_mi_get_block_info(&block_info,-1,pos);
02438 if ((b_type & (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
02439 ((b_type & BLOCK_FIRST) &&
02440 (block_info.rec_len < (uint) share->base.min_pack_length ||
02441 block_info.rec_len > (uint) share->base.max_pack_length)))
02442 {
02443 uint32_t i;
02444 if (param->testflag & T_VERBOSE || searching == 0)
02445 mi_check_print_info(param,
02446 "Wrong bytesec: %3d-%3d-%3d at %10s; Skipped",
02447 block_info.header[0],block_info.header[1],
02448 block_info.header[2],llstr(pos,llbuff));
02449 if (found_record)
02450 goto try_next;
02451 block_info.second_read=0;
02452 searching=1;
02453
02454 for (i=MI_DYN_ALIGN_SIZE ;
02455 i < MI_BLOCK_INFO_HEADER_LENGTH ;
02456 i+= MI_DYN_ALIGN_SIZE)
02457 if (block_info.header[i] >= 1 &&
02458 block_info.header[i] <= MI_MAX_DYN_HEADER_BYTE)
02459 break;
02460 pos+=(ulong) i;
02461 sort_param->start_recpos=pos;
02462 continue;
02463 }
02464 if (b_type & BLOCK_DELETED)
02465 {
02466 bool error=0;
02467 if (block_info.block_len+ (uint) (block_info.filepos-pos) <
02468 share->base.min_block_length)
02469 {
02470 if (!searching)
02471 mi_check_print_info(param,
02472 "Deleted block with impossible length %u at %s",
02473 block_info.block_len,llstr(pos,llbuff));
02474 error=1;
02475 }
02476 else
02477 {
02478 if ((block_info.next_filepos != HA_OFFSET_ERROR &&
02479 block_info.next_filepos >=
02480 info->state->data_file_length) ||
02481 (block_info.prev_filepos != HA_OFFSET_ERROR &&
02482 block_info.prev_filepos >= info->state->data_file_length))
02483 {
02484 if (!searching)
02485 mi_check_print_info(param,
02486 "Delete link points outside datafile at %s",
02487 llstr(pos,llbuff));
02488 error=1;
02489 }
02490 }
02491 if (error)
02492 {
02493 if (found_record)
02494 goto try_next;
02495 searching=1;
02496 pos+= MI_DYN_ALIGN_SIZE;
02497 sort_param->start_recpos=pos;
02498 block_info.second_read=0;
02499 continue;
02500 }
02501 }
02502 else
02503 {
02504 if (block_info.block_len+ (uint) (block_info.filepos-pos) <
02505 share->base.min_block_length ||
02506 block_info.block_len > (uint) share->base.max_pack_length+
02507 MI_SPLIT_LENGTH)
02508 {
02509 if (!searching)
02510 mi_check_print_info(param,
02511 "Found block with impossible length %u at %s; Skipped",
02512 block_info.block_len+ (uint) (block_info.filepos-pos),
02513 llstr(pos,llbuff));
02514 if (found_record)
02515 goto try_next;
02516 searching=1;
02517 pos+= MI_DYN_ALIGN_SIZE;
02518 sort_param->start_recpos=pos;
02519 block_info.second_read=0;
02520 continue;
02521 }
02522 }
02523 if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
02524 {
02525 if (!sort_param->fix_datafile && sort_param->master &&
02526 (b_type & BLOCK_DELETED))
02527 {
02528 info->state->empty+=block_info.block_len;
02529 info->state->del++;
02530 share->state.split++;
02531 }
02532 if (found_record)
02533 goto try_next;
02534 if (searching)
02535 {
02536 pos+=MI_DYN_ALIGN_SIZE;
02537 sort_param->start_recpos=pos;
02538 }
02539 else
02540 pos=block_info.filepos+block_info.block_len;
02541 block_info.second_read=0;
02542 continue;
02543 }
02544
02545 if (!sort_param->fix_datafile && sort_param->master)
02546 share->state.split++;
02547 if (! found_record++)
02548 {
02549 sort_param->find_length=left_length=block_info.rec_len;
02550 sort_param->start_recpos=pos;
02551 if (!sort_param->fix_datafile)
02552 sort_param->filepos=sort_param->start_recpos;
02553 if (sort_param->fix_datafile && (param->testflag & T_EXTEND))
02554 sort_param->pos=block_info.filepos+1;
02555 else
02556 sort_param->pos=block_info.filepos+block_info.block_len;
02557 if (share->base.blobs)
02558 {
02559 if (!(to=mi_alloc_rec_buff(info,block_info.rec_len,
02560 &(sort_param->rec_buff))))
02561 {
02562 if (param->max_record_length >= block_info.rec_len)
02563 {
02564 mi_check_print_error(param,"Not enough memory for blob at %s (need %lu)",
02565 llstr(sort_param->start_recpos,llbuff),
02566 (ulong) block_info.rec_len);
02567 return(1);
02568 }
02569 else
02570 {
02571 mi_check_print_info(param,"Not enough memory for blob at %s (need %lu); Row skipped",
02572 llstr(sort_param->start_recpos,llbuff),
02573 (ulong) block_info.rec_len);
02574 goto try_next;
02575 }
02576 }
02577 }
02578 else
02579 to= sort_param->rec_buff;
02580 }
02581 if (left_length < block_info.data_len || ! block_info.data_len)
02582 {
02583 mi_check_print_info(param,
02584 "Found block with too small length at %s; Skipped",
02585 llstr(sort_param->start_recpos,llbuff));
02586 goto try_next;
02587 }
02588 if (block_info.filepos + block_info.data_len >
02589 sort_param->read_cache.end_of_file)
02590 {
02591 mi_check_print_info(param,
02592 "Found block that points outside data file at %s",
02593 llstr(sort_param->start_recpos,llbuff));
02594 goto try_next;
02595 }
02596
02597
02598
02599
02600
02601 {
02602 uint32_t header_len= (uint) (block_info.filepos - pos);
02603 uint32_t prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len);
02604
02605 if (prefetch_len > block_info.data_len)
02606 prefetch_len= block_info.data_len;
02607 if (prefetch_len)
02608 {
02609 memcpy(to, block_info.header + header_len, prefetch_len);
02610 block_info.filepos+= prefetch_len;
02611 block_info.data_len-= prefetch_len;
02612 left_length-= prefetch_len;
02613 to+= prefetch_len;
02614 }
02615 }
02616 if (block_info.data_len &&
02617 _mi_read_cache(&sort_param->read_cache,to,block_info.filepos,
02618 block_info.data_len,
02619 (found_record == 1 ? READING_NEXT : 0) |
02620 parallel_flag))
02621 {
02622 mi_check_print_info(param,
02623 "Read error for block at: %s (error: %d); Skipped",
02624 llstr(block_info.filepos,llbuff),errno);
02625 goto try_next;
02626 }
02627 left_length-=block_info.data_len;
02628 to+=block_info.data_len;
02629 pos=block_info.next_filepos;
02630 if (pos == HA_OFFSET_ERROR && left_length)
02631 {
02632 mi_check_print_info(param,"Wrong block with wrong total length starting at %s",
02633 llstr(sort_param->start_recpos,llbuff));
02634 goto try_next;
02635 }
02636 if (pos + MI_BLOCK_INFO_HEADER_LENGTH > sort_param->read_cache.end_of_file)
02637 {
02638 mi_check_print_info(param,"Found link that points at %s (outside data file) at %s",
02639 llstr(pos,llbuff2),
02640 llstr(sort_param->start_recpos,llbuff));
02641 goto try_next;
02642 }
02643 } while (left_length);
02644
02645 if (_mi_rec_unpack(info,sort_param->record,sort_param->rec_buff,
02646 sort_param->find_length) != MY_FILE_ERROR)
02647 {
02648 if (sort_param->read_cache.error < 0)
02649 return(1);
02650 if (sort_param->calc_checksum)
02651 info->checksum= mi_checksum(info, sort_param->record);
02652 if ((param->testflag & (T_EXTEND | T_REP)) || searching)
02653 {
02654 if (_mi_rec_check(info, sort_param->record, sort_param->rec_buff,
02655 sort_param->find_length,
02656 (param->testflag & T_QUICK) &&
02657 sort_param->calc_checksum &&
02658 test(info->s->calc_checksum)))
02659 {
02660 mi_check_print_info(param,"Found wrong packed record at %s",
02661 llstr(sort_param->start_recpos,llbuff));
02662 goto try_next;
02663 }
02664 }
02665 if (sort_param->calc_checksum)
02666 param->glob_crc+= info->checksum;
02667 return(0);
02668 }
02669 if (!searching)
02670 mi_check_print_info(param,"Key %d - Found wrong stored record at %s",
02671 sort_param->key+1,
02672 llstr(sort_param->start_recpos,llbuff));
02673 try_next:
02674 pos=(sort_param->start_recpos+=MI_DYN_ALIGN_SIZE);
02675 searching=1;
02676 }
02677 case COMPRESSED_RECORD:
02678 case BLOCK_RECORD:
02679 assert(0);
02680 }
02681 return(1);
02682 }
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700 int sort_write_record(MI_SORT_PARAM *sort_param)
02701 {
02702 int flag;
02703 ulong block_length,reclength;
02704 unsigned char *from;
02705 SORT_INFO *sort_info=sort_param->sort_info;
02706 MI_CHECK *param=sort_info->param;
02707 MI_INFO *info=sort_info->info;
02708 MYISAM_SHARE *share=info->s;
02709
02710 if (sort_param->fix_datafile)
02711 {
02712 switch (sort_info->new_data_file_type) {
02713 case STATIC_RECORD:
02714 if (info->rec_cache.write(sort_param->record, share->base.pack_reclength))
02715 {
02716 mi_check_print_error(param,"%d when writing to datafile",errno);
02717 return(1);
02718 }
02719 sort_param->filepos+=share->base.pack_reclength;
02720 info->s->state.split++;
02721
02722 break;
02723 case DYNAMIC_RECORD:
02724 if (! info->blobs)
02725 from=sort_param->rec_buff;
02726 else
02727 {
02728
02729 reclength=info->s->base.pack_reclength+
02730 _my_calc_total_blob_length(info,sort_param->record)+
02731 ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
02732 MI_DYN_DELETE_BLOCK_HEADER;
02733 if (sort_info->buff_length < reclength)
02734 {
02735 void *tmpptr= NULL;
02736 tmpptr= realloc(sort_info->buff, reclength);
02737 if(tmpptr)
02738 {
02739 sort_info->buff_length=reclength;
02740 sort_info->buff= (unsigned char *)tmpptr;
02741 }
02742 else
02743 {
02744 mi_check_print_error(param,"Could not realloc() sort_info->buff "
02745 " to %ul bytes", reclength);
02746 return(1);
02747 }
02748 }
02749 from= sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
02750 }
02751
02752 info->checksum=mi_checksum(info,sort_param->record);
02753 reclength=_mi_rec_pack(info,from,sort_param->record);
02754 flag=0;
02755
02756
02757 do
02758 {
02759 block_length=reclength+ 3 + test(reclength >= (65520-3));
02760 if (block_length < share->base.min_block_length)
02761 block_length=share->base.min_block_length;
02762 info->update|=HA_STATE_WRITE_AT_END;
02763 block_length=MY_ALIGN(block_length,MI_DYN_ALIGN_SIZE);
02764 if (block_length > MI_MAX_BLOCK_LENGTH)
02765 block_length=MI_MAX_BLOCK_LENGTH;
02766 if (_mi_write_part_record(info,0L,block_length,
02767 sort_param->filepos+block_length,
02768 &from,&reclength,&flag))
02769 {
02770 mi_check_print_error(param,"%d when writing to datafile",errno);
02771 return(1);
02772 }
02773 sort_param->filepos+=block_length;
02774 info->s->state.split++;
02775 } while (reclength);
02776
02777 break;
02778 case COMPRESSED_RECORD:
02779 case BLOCK_RECORD:
02780 assert(0);
02781 }
02782 }
02783 if (sort_param->master)
02784 {
02785 info->state->records++;
02786 if ((param->testflag & T_WRITE_LOOP) &&
02787 (info->state->records % WRITE_COUNT) == 0)
02788 {
02789 char llbuff[22];
02790 printf("%s\r", llstr(info->state->records,llbuff));
02791 fflush(stdout);
02792 }
02793 }
02794 return(0);
02795 }
02796
02797
02798
02799
02800 int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a, const void *b)
02801 {
02802 uint32_t not_used[2];
02803 return (ha_key_cmp(sort_param->seg, *((unsigned char* const *) a), *((unsigned char* const *) b),
02804 USE_WHOLE_KEY, SEARCH_SAME, not_used));
02805 }
02806
02807
02808 int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
02809 {
02810 uint32_t diff_pos[2];
02811 char llbuff[22],llbuff2[22];
02812 SORT_INFO *sort_info=sort_param->sort_info;
02813 MI_CHECK *param= sort_info->param;
02814 int cmp;
02815
02816 if (sort_info->key_block->inited)
02817 {
02818 cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
02819 (unsigned char*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
02820 diff_pos);
02821 if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
02822 ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
02823 (unsigned char*) a, USE_WHOLE_KEY,
02824 SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
02825 else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
02826 {
02827 diff_pos[0]= mi_collect_stats_nonulls_next(sort_param->seg,
02828 sort_param->notnull,
02829 sort_info->key_block->lastkey,
02830 (unsigned char*)a);
02831 }
02832 sort_param->unique[diff_pos[0]-1]++;
02833 }
02834 else
02835 {
02836 cmp= -1;
02837 if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
02838 mi_collect_stats_nonulls_first(sort_param->seg, sort_param->notnull,
02839 (unsigned char*)a);
02840 }
02841 if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0)
02842 {
02843 sort_info->dupp++;
02844 sort_info->info->lastpos=get_record_for_key(sort_info->info,
02845 sort_param->keyinfo,
02846 (unsigned char*) a);
02847 mi_check_print_warning(param,
02848 "Duplicate key for record at %10s against record at %10s",
02849 llstr(sort_info->info->lastpos,llbuff),
02850 llstr(get_record_for_key(sort_info->info,
02851 sort_param->keyinfo,
02852 sort_info->key_block->
02853 lastkey),
02854 llbuff2));
02855 param->testflag|=T_RETRY_WITHOUT_QUICK;
02856 return (sort_delete_record(sort_param));
02857 }
02858 return (sort_insert_key(sort_param,sort_info->key_block,
02859 (unsigned char*) a, HA_OFFSET_ERROR));
02860 }
02861
02862
02863
02864
02865 my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo,
02866 unsigned char *key) {
02867 return _mi_dpos(info,0,key+_mi_keylength(keyinfo,key));
02868 }
02869
02870
02871
02872
02873 int sort_insert_key(MI_SORT_PARAM *sort_param,
02874 register SORT_KEY_BLOCKS *key_block, unsigned char *key,
02875 my_off_t prev_block)
02876 {
02877 uint32_t a_length,t_length,nod_flag;
02878 my_off_t filepos,key_file_length;
02879 unsigned char *anc_buff,*lastkey;
02880 MI_KEY_PARAM s_temp;
02881 MI_INFO *info;
02882 MI_KEYDEF *keyinfo=sort_param->keyinfo;
02883 SORT_INFO *sort_info= sort_param->sort_info;
02884 MI_CHECK *param=sort_info->param;
02885
02886 anc_buff=key_block->buff;
02887 info=sort_info->info;
02888 lastkey=key_block->lastkey;
02889 nod_flag= (key_block == sort_info->key_block ? 0 :
02890 info->s->base.key_reflength);
02891
02892 if (!key_block->inited)
02893 {
02894 key_block->inited=1;
02895 if (key_block == sort_info->key_block_end)
02896 {
02897 mi_check_print_error(param,"To many key-block-levels; Try increasing sort_key_blocks");
02898 return(1);
02899 }
02900 a_length=2+nod_flag;
02901 key_block->end_pos=anc_buff+2;
02902 lastkey=0;
02903 }
02904 else
02905 a_length=mi_getint(anc_buff);
02906
02907
02908 if (nod_flag)
02909 _mi_kpointer(info,key_block->end_pos,prev_block);
02910
02911 t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
02912 (unsigned char*) 0,lastkey,lastkey,key,
02913 &s_temp);
02914 (*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp);
02915 a_length+=t_length;
02916 mi_putint(anc_buff,a_length,nod_flag);
02917 key_block->end_pos+=t_length;
02918 if (a_length <= keyinfo->block_length)
02919 {
02920 _mi_move_key(keyinfo,key_block->lastkey,key);
02921 key_block->last_length=a_length-t_length;
02922 return(0);
02923 }
02924
02925
02926 mi_putint(anc_buff,key_block->last_length,nod_flag);
02927 memset(anc_buff+key_block->last_length, 0,
02928 keyinfo->block_length - key_block->last_length);
02929 key_file_length=info->state->key_file_length;
02930 if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
02931 return(1);
02932
02933
02934 if (key_file_length == info->state->key_file_length)
02935 {
02936 if (_mi_write_keypage(info, keyinfo, filepos, DFLT_INIT_HITS, anc_buff))
02937 return(1);
02938 }
02939 else if (my_pwrite(info->s->kfile,(unsigned char*) anc_buff,
02940 (uint) keyinfo->block_length,filepos, param->myf_rw))
02941 return(1);
02942
02943
02944 if (sort_insert_key(sort_param,key_block+1,key_block->lastkey,filepos))
02945 return(1);
02946
02947
02948 key_block->inited=0;
02949 return(sort_insert_key(sort_param, key_block,key,prev_block));
02950 }
02951
02952
02953
02954
02955 int sort_delete_record(MI_SORT_PARAM *sort_param)
02956 {
02957 uint32_t i;
02958 int old_file,error;
02959 unsigned char *key;
02960 SORT_INFO *sort_info=sort_param->sort_info;
02961 MI_CHECK *param=sort_info->param;
02962 MI_INFO *info=sort_info->info;
02963
02964 if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
02965 {
02966 mi_check_print_error(param,
02967 "Quick-recover aborted; Run recovery without switch -q or with switch -qq");
02968 return(1);
02969 }
02970 if (info->s->options & HA_OPTION_COMPRESS_RECORD)
02971 {
02972 mi_check_print_error(param,
02973 "Recover aborted; Can't run standard recovery on compressed tables with errors in data-file. Use switch 'myisamchk --safe-recover' to fix it\n",stderr);;
02974 return(1);
02975 }
02976
02977 old_file=info->dfile;
02978 info->dfile=info->rec_cache.file;
02979 if (sort_info->current_key)
02980 {
02981 key=info->lastkey+info->s->base.max_key_length;
02982 if ((error=(*info->s->read_rnd)(info,sort_param->record,info->lastpos,0)) &&
02983 error != HA_ERR_RECORD_DELETED)
02984 {
02985 mi_check_print_error(param,"Can't read record to be removed");
02986 info->dfile=old_file;
02987 return(1);
02988 }
02989
02990 for (i=0 ; i < sort_info->current_key ; i++)
02991 {
02992 uint32_t key_length=_mi_make_key(info,i,key,sort_param->record,info->lastpos);
02993 if (_mi_ck_delete(info,i,key,key_length))
02994 {
02995 mi_check_print_error(param,"Can't delete key %d from record to be removed",i+1);
02996 info->dfile=old_file;
02997 return(1);
02998 }
02999 }
03000 if (sort_param->calc_checksum)
03001 param->glob_crc-=(*info->s->calc_checksum)(info, sort_param->record);
03002 }
03003 error= info->rec_cache.flush() || (*info->s->delete_record)(info);
03004 info->dfile=old_file;
03005 info->state->records--;
03006 return(error);
03007 }
03008
03009
03010
03011 int flush_pending_blocks(MI_SORT_PARAM *sort_param)
03012 {
03013 uint32_t nod_flag,length;
03014 my_off_t filepos,key_file_length;
03015 SORT_KEY_BLOCKS *key_block;
03016 SORT_INFO *sort_info= sort_param->sort_info;
03017 myf myf_rw=sort_info->param->myf_rw;
03018 MI_INFO *info=sort_info->info;
03019 MI_KEYDEF *keyinfo=sort_param->keyinfo;
03020
03021 filepos= HA_OFFSET_ERROR;
03022 nod_flag=0;
03023 for (key_block=sort_info->key_block ; key_block->inited ; key_block++)
03024 {
03025 key_block->inited=0;
03026 length=mi_getint(key_block->buff);
03027 if (nod_flag)
03028 _mi_kpointer(info,key_block->end_pos,filepos);
03029 key_file_length=info->state->key_file_length;
03030 memset(key_block->buff+length, 0, keyinfo->block_length-length);
03031 if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
03032 return(1);
03033
03034
03035 if (key_file_length == info->state->key_file_length)
03036 {
03037 if (_mi_write_keypage(info, keyinfo, filepos,
03038 DFLT_INIT_HITS, key_block->buff))
03039 return(1);
03040 }
03041 else if (my_pwrite(info->s->kfile,(unsigned char*) key_block->buff,
03042 (uint) keyinfo->block_length,filepos, myf_rw))
03043 return(1);
03044 nod_flag=1;
03045 }
03046 info->s->state.key_root[sort_param->key]=filepos;
03047 return(0);
03048 }
03049
03050
03051
03052 static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint32_t blocks,
03053 uint32_t buffer_length)
03054 {
03055 register uint32_t i;
03056 SORT_KEY_BLOCKS *block;
03057
03058 if (!(block=(SORT_KEY_BLOCKS*) malloc((sizeof(SORT_KEY_BLOCKS)+
03059 buffer_length+IO_SIZE)*blocks)))
03060 {
03061 mi_check_print_error(param,"Not enough memory for sort-key-blocks");
03062 return(0);
03063 }
03064 for (i=0 ; i < blocks ; i++)
03065 {
03066 block[i].inited=0;
03067 block[i].buff=(unsigned char*) (block+blocks)+(buffer_length+IO_SIZE)*i;
03068 }
03069 return(block);
03070 }
03071
03072
03073
03074
03075 int test_if_almost_full(MI_INFO *info)
03076 {
03077 if (info->s->options & HA_OPTION_COMPRESS_RECORD)
03078 return 0;
03079 return (my_off_t)(lseek(info->s->kfile, 0L, SEEK_END) / 10 * 9) >
03080 (my_off_t) info->s->base.max_key_file_length ||
03081 (my_off_t)(lseek(info->dfile, 0L, SEEK_END) / 10 * 9) >
03082 (my_off_t) info->s->base.max_data_file_length;
03083 }
03084
03085
03086
03087
03088 int write_data_suffix(SORT_INFO *sort_info, bool fix_datafile)
03089 {
03090 MI_INFO *info=sort_info->info;
03091
03092 if (info->s->options & HA_OPTION_COMPRESS_RECORD && fix_datafile)
03093 {
03094 unsigned char buff[MEMMAP_EXTRA_MARGIN];
03095 memset(buff, 0, sizeof(buff));
03096 if (info->rec_cache.write(buff, sizeof(buff)))
03097 {
03098 mi_check_print_error(sort_info->param,
03099 "%d when writing to datafile",errno);
03100 return 1;
03101 }
03102 sort_info->param->read_cache.end_of_file+=sizeof(buff);
03103 }
03104 return 0;
03105 }
03106
03107
03108
03109 int update_state_info(MI_CHECK *param, MI_INFO *info,uint32_t update)
03110 {
03111 MYISAM_SHARE *share=info->s;
03112
03113 if (update & UPDATE_OPEN_COUNT)
03114 {
03115 share->state.open_count=0;
03116 share->global_changed=0;
03117 }
03118 if (update & UPDATE_STAT)
03119 {
03120 uint32_t i, key_parts= mi_uint2korr(share->state.header.key_parts);
03121 share->state.rec_per_key_rows=info->state->records;
03122 share->state.changed&= ~STATE_NOT_ANALYZED;
03123 if (info->state->records)
03124 {
03125 for (i=0; i<key_parts; i++)
03126 {
03127 if (!(share->state.rec_per_key_part[i]=param->rec_per_key_part[i]))
03128 share->state.changed|= STATE_NOT_ANALYZED;
03129 }
03130 }
03131 }
03132 if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC))
03133 {
03134 if (update & UPDATE_TIME)
03135 {
03136 share->state.check_time= (long) time((time_t*) 0);
03137 if (!share->state.create_time)
03138 share->state.create_time=share->state.check_time;
03139 }
03140
03141
03142
03143
03144
03145
03146 if (info->lock_type == F_WRLCK)
03147 share->state.state= *info->state;
03148 if (mi_state_info_write(share->kfile,&share->state,1+2))
03149 goto err;
03150 share->changed=0;
03151 }
03152 {
03153 int error;
03154 uint32_t r_locks=share->r_locks,w_locks=share->w_locks;
03155 share->r_locks= share->w_locks= share->tot_locks= 0;
03156 error=_mi_writeinfo(info,WRITEINFO_NO_UNLOCK);
03157 share->r_locks=r_locks;
03158 share->w_locks=w_locks;
03159 share->tot_locks=r_locks+w_locks;
03160 if (!error)
03161 return 0;
03162 }
03163 err:
03164 mi_check_print_error(param,"%d when updating keyfile",errno);
03165 return 1;
03166 }
03167
03168
03169
03170
03171
03172
03173
03174
03175
03176
03177
03178
03179
03180
03181 void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
03182 bool repair_only)
03183 {
03184 unsigned char *record= 0;
03185
03186 if (!info->s->base.auto_key ||
03187 ! mi_is_key_active(info->s->state.key_map, info->s->base.auto_key - 1))
03188 {
03189 if (!(param->testflag & T_VERY_SILENT))
03190 mi_check_print_info(param,
03191 "Table: %s doesn't have an auto increment key\n",
03192 param->isam_file_name);
03193 return;
03194 }
03195 if (!(param->testflag & T_SILENT) &&
03196 !(param->testflag & T_REP))
03197 printf("Updating MyISAM file: %s\n", param->isam_file_name);
03198
03199
03200
03201
03202 if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
03203 {
03204 mi_check_print_error(param,"Not enough memory for extra record");
03205 return;
03206 }
03207
03208 mi_extra(info,HA_EXTRA_KEYREAD,0);
03209 if (mi_rlast(info, record, info->s->base.auto_key-1))
03210 {
03211 if (errno != HA_ERR_END_OF_FILE)
03212 {
03213 mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
03214 free(mi_get_rec_buff_ptr(info, record));
03215 mi_check_print_error(param,"%d when reading last record",errno);
03216 return;
03217 }
03218 if (!repair_only)
03219 info->s->state.auto_increment=param->auto_increment_value;
03220 }
03221 else
03222 {
03223 uint64_t auto_increment= retrieve_auto_increment(info, record);
03224 set_if_bigger(info->s->state.auto_increment,auto_increment);
03225 if (!repair_only)
03226 set_if_bigger(info->s->state.auto_increment, param->auto_increment_value);
03227 }
03228 mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
03229 free(mi_get_rec_buff_ptr(info, record));
03230 update_state_info(param, info, UPDATE_AUTO_INC);
03231 return;
03232 }
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286 void update_key_parts(MI_KEYDEF *keyinfo, ulong *rec_per_key_part,
03287 uint64_t *unique, uint64_t *notnull,
03288 uint64_t records)
03289 {
03290 uint64_t count=0,tmp, unique_tuples;
03291 uint64_t tuples= records;
03292 uint32_t parts;
03293 for (parts=0 ; parts < keyinfo->keysegs ; parts++)
03294 {
03295 count+=unique[parts];
03296 unique_tuples= count + 1;
03297 if (notnull)
03298 {
03299 tuples= notnull[parts];
03300
03301
03302
03303
03304
03305 unique_tuples -= (records - notnull[parts]);
03306 }
03307
03308 if (unique_tuples == 0)
03309 tmp= 1;
03310 else if (count == 0)
03311 tmp= tuples;
03312 else
03313 tmp= (tuples + unique_tuples/2) / unique_tuples;
03314
03315
03316
03317
03318
03319 if (tmp < 1)
03320 tmp= 1;
03321 if (tmp >= (uint64_t) ~(ulong) 0)
03322 tmp=(uint64_t) ~(ulong) 0;
03323
03324 *rec_per_key_part=(ulong) tmp;
03325 rec_per_key_part++;
03326 }
03327 }
03328
03329
03330 static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length)
03331 {
03332 ha_checksum crc;
03333 const unsigned char *end=buf+length;
03334 for (crc=0; buf != end; buf++)
03335 crc=((crc << 1) + *((unsigned char*) buf)) +
03336 test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1)));
03337 return crc;
03338 }
03339
03340 static bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows)
03341 {
03342 uint32_t key_maxlength=key->maxlength;
03343 return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY) &&
03344 ((uint64_t) rows * key_maxlength >
03345 (uint64_t) MAX_FILE_SIZE));
03346 }
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357 void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows)
03358 {
03359 MYISAM_SHARE *share=info->s;
03360 MI_KEYDEF *key=share->keyinfo;
03361 uint32_t i;
03362
03363 assert(info->state->records == 0 &&
03364 (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES));
03365 for (i=0 ; i < share->base.keys ; i++,key++)
03366 {
03367 if (!(key->flag & (HA_NOSAME | HA_AUTO_KEY)) &&
03368 ! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1)
03369 {
03370 mi_clear_key_active(share->state.key_map, i);
03371 info->update|= HA_STATE_CHANGED;
03372 }
03373 }
03374 }
03375
03376
03377
03378
03379
03380
03381
03382
03383 bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
03384 uint64_t key_map, bool force)
03385 {
03386 MYISAM_SHARE *share=info->s;
03387 MI_KEYDEF *key=share->keyinfo;
03388 uint32_t i;
03389
03390
03391
03392
03393
03394 if (! mi_is_any_key_active(key_map))
03395 return false;
03396 for (i=0 ; i < share->base.keys ; i++,key++)
03397 {
03398 if (!force && mi_too_big_key_for_sort(key,rows))
03399 return false;
03400 }
03401 return true;
03402 }
03403
03404
03405 static void
03406 set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share)
03407 {
03408 if ((sort_info->new_data_file_type=share->data_file_type) ==
03409 COMPRESSED_RECORD && sort_info->param->testflag & T_UNPACK)
03410 {
03411 MYISAM_SHARE tmp;
03412
03413 if (share->options & HA_OPTION_PACK_RECORD)
03414 sort_info->new_data_file_type = DYNAMIC_RECORD;
03415 else
03416 sort_info->new_data_file_type = STATIC_RECORD;
03417
03418
03419 memcpy(&tmp, share, sizeof(*share));
03420 tmp.options= ~HA_OPTION_COMPRESS_RECORD;
03421 mi_setup_functions(&tmp);
03422 share->delete_record=tmp.delete_record;
03423 }
03424 }