~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mi_check.c

  • Committer: Mark Atwood
  • Date: 2008-10-03 01:39:40 UTC
  • mto: This revision was merged to the branch mainline in revision 437.
  • Revision ID: mark@fallenpegasus.com-20081003013940-mvefjo725dltz41h
rename logging_noop to logging_query

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/* Describe, check and repair of MyISAM tables */
17
17
 
40
40
  only. And it is sufficient to calculate the checksum once only.
41
41
*/
42
42
 
43
 
#include "myisam_priv.h"
44
 
#include <drizzled/internal/m_string.h>
 
43
#include "myisamdef.h"
45
44
#include <stdarg.h>
 
45
#include <mysys/my_getopt.h>
46
46
#ifdef HAVE_SYS_VADVISE_H
47
47
#include <sys/vadvise.h>
48
48
#endif
49
 
#ifdef HAVE_SYS_TYPES
50
 
#include <sys/types.h>
51
 
#endif
52
49
#ifdef HAVE_SYS_MMAN_H
53
50
#include <sys/mman.h>
54
51
#endif
55
 
#include <drizzled/util/test.h>
56
 
#include <drizzled/error.h>
57
 
 
58
 
#include <algorithm>
59
 
 
60
 
using namespace std;
61
 
using namespace drizzled;
62
 
using namespace drizzled::internal;
63
 
 
64
 
 
65
 
#define my_off_t2double(A)  ((double) (my_off_t) (A))
66
 
 
67
 
/* Functions defined in this file */
68
 
 
69
 
static int check_k_link(MI_CHECK *param, MI_INFO *info,uint32_t nr);
 
52
 
 
53
#ifndef USE_RAID
 
54
#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
 
55
#define my_raid_delete(A,B,C) my_delete(A,B)
 
56
#endif
 
57
 
 
58
        /* Functions defined in this file */
 
59
 
 
60
static int check_k_link(MI_CHECK *param, MI_INFO *info,uint nr);
70
61
static int chk_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
71
 
                     my_off_t page, unsigned char *buff, ha_rows *keys,
72
 
                     ha_checksum *key_checksum, uint32_t level);
73
 
static uint32_t isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo);
 
62
                     my_off_t page, uchar *buff, ha_rows *keys,
 
63
                     ha_checksum *key_checksum, uint level);
 
64
static uint isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo);
74
65
static ha_checksum calc_checksum(ha_rows count);
75
66
static int writekeys(MI_SORT_PARAM *sort_param);
76
67
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
77
 
                          my_off_t pagepos, int new_file);
78
 
int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
79
 
int sort_get_next_record(MI_SORT_PARAM *sort_param);
80
 
int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b);
81
 
int sort_key_write(MI_SORT_PARAM *sort_param, const void *a);
82
 
my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
83
 
                            unsigned char *key);
84
 
int sort_insert_key(MI_SORT_PARAM  *sort_param,
85
 
                    register SORT_KEY_BLOCKS *key_block,
86
 
                    unsigned char *key, my_off_t prev_block);
87
 
int sort_delete_record(MI_SORT_PARAM *sort_param);
88
 
 
 
68
                          my_off_t pagepos, File new_file);
 
69
static int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
 
70
static int sort_get_next_record(MI_SORT_PARAM *sort_param);
 
71
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b);
 
72
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a);
 
73
static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
 
74
                                uchar *key);
 
75
static int sort_insert_key(MI_SORT_PARAM  *sort_param,
 
76
                           register SORT_KEY_BLOCKS *key_block,
 
77
                           uchar *key, my_off_t prev_block);
 
78
static int sort_delete_record(MI_SORT_PARAM *sort_param);
89
79
/*static int flush_pending_blocks(MI_CHECK *param);*/
90
 
static SORT_KEY_BLOCKS  *alloc_key_blocks(MI_CHECK *param, uint32_t blocks,
91
 
                                          uint32_t buffer_length);
92
 
static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length);
 
80
static SORT_KEY_BLOCKS  *alloc_key_blocks(MI_CHECK *param, uint blocks,
 
81
                                          uint buffer_length);
 
82
static ha_checksum mi_byte_checksum(const uchar *buf, uint length);
93
83
static void set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share);
94
84
 
95
85
void myisamchk_init(MI_CHECK *param)
127
117
  if (share->state.open_count != (uint) (info->s->global_changed ? 1 : 0))
128
118
  {
129
119
    /* Don't count this as a real warning, as check can correct this ! */
130
 
    uint32_t save=param->warning_printed;
 
120
    uint save=param->warning_printed;
131
121
    mi_check_print_warning(param,
132
 
                           share->state.open_count==1 ?
133
 
                           "%d client is using or hasn't closed the table properly" :
 
122
                           share->state.open_count==1 ? 
 
123
                           "%d client is using or hasn't closed the table properly" : 
134
124
                           "%d clients are using or haven't closed the table properly",
135
125
                           share->state.open_count);
136
126
    /* If this will be fixed by the check, forget the warning */
142
132
 
143
133
        /* Check delete links */
144
134
 
145
 
int chk_del(MI_CHECK *param, register MI_INFO *info, uint32_t test_flag)
 
135
int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag)
146
136
{
147
137
  register ha_rows i;
148
 
  uint32_t delete_link_length;
 
138
  uint delete_link_length;
149
139
  my_off_t empty, next_link, old_link= 0;
150
140
  char buff[22],buff2[22];
151
141
 
177
167
        printf(" %9s",llstr(next_link,buff));
178
168
      if (next_link >= info->state->data_file_length)
179
169
        goto wrong;
180
 
      if (my_pread(info->dfile, (unsigned char*) buff,delete_link_length,
 
170
      if (my_pread(info->dfile, (uchar*) buff,delete_link_length,
181
171
                   next_link,MYF(MY_NABP)))
182
172
      {
183
173
        if (test_flag & T_VERBOSE) puts("");
208
198
      else
209
199
      {
210
200
        param->record_checksum+=(ha_checksum) next_link;
211
 
        next_link=_mi_rec_pos(info->s,(unsigned char*) buff+1);
 
201
        next_link=_mi_rec_pos(info->s,(uchar*) buff+1);
212
202
        empty+=info->s->base.pack_reclength;
213
203
      }
214
204
    }
249
239
 
250
240
        /* Check delete links in index file */
251
241
 
252
 
static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint32_t nr)
 
242
static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr)
253
243
{
254
244
  my_off_t next_link;
255
 
  uint32_t block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH;
 
245
  uint block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH;
256
246
  ha_rows records;
257
247
  char llbuff[21], llbuff2[21];
258
 
  unsigned char *buff;
 
248
  uchar *buff;
259
249
 
260
250
  if (param->testflag & T_VERBOSE)
261
 
    printf("block_size %4u:", block_size);
 
251
    printf("block_size %4u:", block_size); /* purecov: tested */
262
252
 
263
253
  next_link=info->s->state.key_del[nr];
264
254
  records= (ha_rows) (info->state->key_file_length / block_size);
272
262
    /* Key blocks must lay within the key file length entirely. */
273
263
    if (next_link + block_size > info->state->key_file_length)
274
264
    {
 
265
      /* purecov: begin tested */
275
266
      mi_check_print_error(param, "Invalid key block position: %s  "
276
267
                           "key block size: %u  file_length: %s",
277
268
                           llstr(next_link, llbuff), block_size,
278
269
                           llstr(info->state->key_file_length, llbuff2));
279
270
      return(1);
 
271
      /* purecov: end */
280
272
    }
281
273
 
282
274
    /* Key blocks must be aligned at MI_MIN_KEY_BLOCK_LENGTH. */
283
275
    if (next_link & (MI_MIN_KEY_BLOCK_LENGTH - 1))
284
276
    {
 
277
      /* purecov: begin tested */
285
278
      mi_check_print_error(param, "Mis-aligned key block: %s  "
286
279
                           "minimum key block length: %u",
287
280
                           llstr(next_link, llbuff), MI_MIN_KEY_BLOCK_LENGTH);
288
281
      return(1);
 
282
      /* purecov: end */
289
283
    }
290
284
 
291
285
    /*
293
287
      If the key cache block size is smaller than block_size, we can so
294
288
      avoid unecessary eviction of cache block.
295
289
    */
296
 
    if (!(buff=key_cache_read(info->s->getKeyCache(),
 
290
    if (!(buff=key_cache_read(info->s->key_cache,
297
291
                              info->s->kfile, next_link, DFLT_INIT_HITS,
298
 
                              (unsigned char*) info->buff, MI_MIN_KEY_BLOCK_LENGTH,
 
292
                              (uchar*) info->buff, MI_MIN_KEY_BLOCK_LENGTH,
299
293
                              MI_MIN_KEY_BLOCK_LENGTH, 1)))
300
294
    {
 
295
      /* purecov: begin tested */
301
296
      mi_check_print_error(param, "key cache read error for block: %s",
302
297
                           llstr(next_link,llbuff));
303
298
      return(1);
 
299
      /* purecov: end */
304
300
    }
305
301
    next_link=mi_sizekorr(buff);
306
302
    records--;
328
324
  if (!(param->testflag & T_SILENT)) puts("- check file-size");
329
325
 
330
326
  /* The following is needed if called externally (not from myisamchk) */
331
 
  flush_key_blocks(info->s->getKeyCache(),
 
327
  flush_key_blocks(info->s->key_cache,
332
328
                   info->s->kfile, FLUSH_FORCE_WRITE);
333
329
 
334
 
  size= lseek(info->s->kfile, 0, SEEK_END);
 
330
  size= my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(MY_THREADSAFE));
335
331
  if ((skr=(my_off_t) info->state->key_file_length) != size)
336
332
  {
337
333
    /* Don't give error if file generated by myisampack */
355
351
                           llstr(info->state->key_file_length,buff),
356
352
                           llstr(info->s->base.max_key_file_length-1,buff));
357
353
 
358
 
  size=lseek(info->dfile,0L,SEEK_END);
 
354
  size=my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
359
355
  skr=(my_off_t) info->state->data_file_length;
360
356
  if (info->s->options & HA_OPTION_COMPRESS_RECORD)
361
357
    skr+= MEMMAP_EXTRA_MARGIN;
396
392
 
397
393
int chk_key(MI_CHECK *param, register MI_INFO *info)
398
394
{
399
 
  uint32_t key,found_keys=0,full_text_keys=0,result=0;
 
395
  uint key,found_keys=0,full_text_keys=0,result=0;
400
396
  ha_rows keys;
401
397
  ha_checksum old_record_checksum,init_checksum;
402
398
  my_off_t all_keydata,all_totaldata,key_totlength,length;
444
440
    found_keys++;
445
441
 
446
442
    param->record_checksum=init_checksum;
447
 
 
 
443
    
448
444
    memset(&param->unique_count, 0, sizeof(param->unique_count));
449
445
    memset(&param->notnull_count, 0, sizeof(param->notnull_count));
450
446
 
459
455
                  llstr(share->state.key_root[key],buff));
460
456
      if (!(param->testflag & T_INFO))
461
457
        return(-1);
462
 
      result= UINT32_MAX;
 
458
      result= -1;
463
459
      continue;
464
460
    }
465
461
    param->key_file_blocks+=keyinfo->block_length;
478
474
                    llstr(info->state->records,buff2));
479
475
        if (!(param->testflag & T_INFO))
480
476
        return(-1);
481
 
        result= UINT32_MAX;
 
477
        result= -1;
482
478
        continue;
483
479
      }
484
480
      if (found_keys - full_text_keys == 1 &&
495
491
          mi_check_print_error(param,"Key 1 doesn't point at all records");
496
492
        if (!(param->testflag & T_INFO))
497
493
          return(-1);
498
 
        result= UINT32_MAX;
 
494
        result= -1;
499
495
        continue;
500
496
      }
501
497
    }
524
520
      /* Check that there isn't a row with auto_increment = 0 in the table */
525
521
      mi_extra(info,HA_EXTRA_KEYREAD,0);
526
522
      memset(info->lastkey, 0, keyinfo->seg->length);
527
 
      if (!mi_rkey(info, info->rec_buff, key, (const unsigned char*) info->lastkey,
 
523
      if (!mi_rkey(info, info->rec_buff, key, (const uchar*) info->lastkey,
528
524
                   (key_part_map)1, HA_READ_KEY_EXACT))
529
525
      {
530
526
        /* Don't count this as a real warning, as myisamchk can't correct it */
531
 
        uint32_t save=param->warning_printed;
 
527
        uint save=param->warning_printed;
532
528
        mi_check_print_warning(param, "Found row where the auto_increment "
533
529
                               "column has the value 0");
534
530
        param->warning_printed=save;
550
546
    if (param->testflag & T_STATISTICS)
551
547
      update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
552
548
                       param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
553
 
                       param->notnull_count: NULL,
 
549
                       param->notnull_count: NULL, 
554
550
                       (uint64_t)info->state->records);
555
551
  }
556
552
  if (param->testflag & T_INFO)
577
573
 
578
574
 
579
575
static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
580
 
                     my_off_t page, unsigned char *buff, ha_rows *keys,
581
 
                     ha_checksum *key_checksum, uint32_t level)
 
576
                     my_off_t page, uchar *buff, ha_rows *keys,
 
577
                     ha_checksum *key_checksum, uint level)
582
578
{
583
579
  char llbuff[22],llbuff2[22];
584
580
 
585
581
  /* Key blocks must lay within the key file length entirely. */
586
582
  if (page + keyinfo->block_length > info->state->key_file_length)
587
583
  {
 
584
    /* purecov: begin tested */
588
585
    /* Give it a chance to fit in the real file size. */
589
 
    my_off_t max_length= lseek(info->s->kfile, 0, SEEK_END);
 
586
    my_off_t max_length= my_seek(info->s->kfile, 0L, MY_SEEK_END,
 
587
                                 MYF(MY_THREADSAFE));
590
588
    mi_check_print_error(param, "Invalid key block position: %s  "
591
589
                         "key block size: %u  file_length: %s",
592
590
                         llstr(page, llbuff), keyinfo->block_length,
596
594
    /* Fix the remebered key file length. */
597
595
    info->state->key_file_length= (max_length &
598
596
                                   ~ (my_off_t) (keyinfo->block_length - 1));
 
597
    /* purecov: end */
599
598
  }
600
599
 
601
600
  /* Key blocks must be aligned at MI_MIN_KEY_BLOCK_LENGTH. */
602
601
  if (page & (MI_MIN_KEY_BLOCK_LENGTH - 1))
603
602
  {
 
603
    /* purecov: begin tested */
604
604
    mi_check_print_error(param, "Mis-aligned key block: %s  "
605
605
                         "minimum key block length: %u",
606
606
                         llstr(page, llbuff), MI_MIN_KEY_BLOCK_LENGTH);
607
607
    goto err;
 
608
    /* purecov: end */
608
609
  }
609
610
 
610
611
  if (!_mi_fetch_keypage(info,keyinfo,page, DFLT_INIT_HITS,buff,0))
619
620
 
620
621
  return(0);
621
622
 
 
623
  /* purecov: begin tested */
622
624
err:
623
625
  return(1);
 
626
  /* purecov: end */
624
627
}
625
628
 
626
629
 
641
644
 
642
645
static
643
646
void mi_collect_stats_nonulls_first(HA_KEYSEG *keyseg, uint64_t *notnull,
644
 
                                    unsigned char *key)
 
647
                                    uchar *key)
645
648
{
646
 
  uint32_t first_null, kp;
 
649
  uint first_null, kp;
647
650
  first_null= ha_find_null(keyseg, key) - keyseg;
648
651
  /*
649
652
    All prefix tuples that don't include keypart_{first_null} are not-null
670
673
    1. Find out which prefix tuples of last_key don't contain NULLs, and
671
674
       update the array of notnull counters accordingly.
672
675
    2. Find the first keypart number where the prev_key and last_key tuples
673
 
       are different(A), or last_key has NULL value(B), and return it, so the
674
 
       caller can count number of unique tuples for each key prefix. We don't
675
 
       need (B) to be counted, and that is compensated back in
 
676
       are different(A), or last_key has NULL value(B), and return it, so the 
 
677
       caller can count number of unique tuples for each key prefix. We don't 
 
678
       need (B) to be counted, and that is compensated back in 
676
679
       update_key_parts().
677
680
 
678
681
  RETURN
681
684
 
682
685
static
683
686
int mi_collect_stats_nonulls_next(HA_KEYSEG *keyseg, uint64_t *notnull,
684
 
                                  unsigned char *prev_key, unsigned char *last_key)
 
687
                                  uchar *prev_key, uchar *last_key)
685
688
{
686
 
  uint32_t diffs[2];
687
 
  uint32_t first_null_seg, kp;
 
689
  uint diffs[2];
 
690
  uint first_null_seg, kp;
688
691
  HA_KEYSEG *seg;
689
692
 
690
 
  /*
 
693
  /* 
691
694
     Find the first keypart where values are different or either of them is
692
695
     NULL. We get results in diffs array:
693
696
     diffs[0]= 1 + number of first different keypart
695
698
                      last_key that is NULL or different from corresponding
696
699
                      value in prev_key.
697
700
  */
698
 
  ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY,
 
701
  ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY, 
699
702
             SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diffs);
700
703
  seg= keyseg + diffs[0] - 1;
701
704
 
704
707
  for (kp= 0; kp < first_null_seg; kp++)
705
708
    notnull[kp]++;
706
709
 
707
 
  /*
 
710
  /* 
708
711
    Return 1+ number of first key part where values differ. Don't care if
709
712
    these were NULLs and not .... We compensate for that in
710
713
    update_key_parts.
716
719
        /* Check if index is ok */
717
720
 
718
721
static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
719
 
                     my_off_t page, unsigned char *buff, ha_rows *keys,
720
 
                     ha_checksum *key_checksum, uint32_t level)
 
722
                     my_off_t page, uchar *buff, ha_rows *keys,
 
723
                     ha_checksum *key_checksum, uint level)
721
724
{
722
725
  int flag;
723
 
  uint32_t used_length,comp_flag,nod_flag,key_length=0;
724
 
  unsigned char key[HA_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos;
 
726
  uint used_length,comp_flag,nod_flag,key_length=0;
 
727
  uchar key[HA_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos;
725
728
  my_off_t next_page,record;
726
729
  char llbuff[22];
727
 
  uint32_t diff_pos[2];
 
730
  uint diff_pos[2];
728
731
 
729
 
  if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
 
732
  if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
730
733
  {
731
734
    mi_check_print_error(param,"Not enough memory for keyblock");
732
735
    return(-1);
795
798
                     diff_pos);
796
799
        else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
797
800
        {
798
 
          diff_pos[0]= mi_collect_stats_nonulls_next(keyinfo->seg,
 
801
          diff_pos[0]= mi_collect_stats_nonulls_next(keyinfo->seg, 
799
802
                                                  param->notnull_count,
800
803
                                                  info->lastkey, key);
801
804
        }
802
805
        param->unique_count[diff_pos[0]-1]++;
803
806
      }
804
807
      else
805
 
      {
 
808
      {  
806
809
        if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
807
810
          mi_collect_stats_nonulls_first(keyinfo->seg, param->notnull_count,
808
811
                                         key);
809
812
      }
810
813
    }
811
 
    (*key_checksum)+= mi_byte_checksum((unsigned char*) key,
 
814
    (*key_checksum)+= mi_byte_checksum((uchar*) key,
812
815
                                       key_length- info->s->rec_reflength);
813
816
    record= _mi_dpos(info,0,key+key_length);
814
817
    if (record >= info->state->data_file_length)
824
827
                llstr(page,llbuff), used_length, (keypos - buff));
825
828
    goto err;
826
829
  }
827
 
  free(temp_buff);
 
830
  my_afree((uchar*) temp_buff);
828
831
  return(0);
829
832
 err:
830
 
  free(temp_buff);
 
833
  my_afree((uchar*) temp_buff);
831
834
  return(1);
832
835
} /* chk_index */
833
836
 
856
859
 
857
860
        /* Calc length of key in normal isam */
858
861
 
859
 
static uint32_t isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo)
 
862
static uint isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo)
860
863
{
861
 
  uint32_t length;
 
864
  uint length;
862
865
  HA_KEYSEG *keyseg;
863
866
 
864
867
  length= info->s->rec_reflength;
878
881
  ha_rows records, del_blocks;
879
882
  my_off_t used, empty, pos, splits, start_recpos= 0,
880
883
           del_length, link_used, start_block;
881
 
  unsigned char *record= NULL, *to= NULL;
 
884
  uchar *record= NULL, *to= NULL;
882
885
  char llbuff[22],llbuff2[22],llbuff3[22];
883
886
  ha_checksum intern_record_checksum;
884
887
  ha_checksum key_checksum[HA_MAX_POSSIBLE_KEY];
894
897
      puts("- check record links");
895
898
  }
896
899
 
897
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
 
900
  if (!mi_alloc_rec_buff(info, -1, &record))
898
901
  {
899
902
    mi_check_print_error(param,"Not enough memory for record");
900
903
    return(-1);
928
931
      goto err2;
929
932
    switch (info->s->data_file_type) {
930
933
    case STATIC_RECORD:
931
 
      if (my_b_read(&param->read_cache,(unsigned char*) record,
 
934
      if (my_b_read(&param->read_cache,(uchar*) record,
932
935
                    info->s->base.pack_reclength))
933
936
        goto err;
934
937
      start_recpos=pos;
948
951
      block_info.next_filepos=pos;
949
952
      do
950
953
      {
951
 
        if (_mi_read_cache(&param->read_cache,(unsigned char*) block_info.header,
 
954
        if (_mi_read_cache(&param->read_cache,(uchar*) block_info.header,
952
955
                           (start_block=block_info.next_filepos),
953
956
                           sizeof(block_info.header),
954
957
                           (flag ? 0 : READING_NEXT) | READING_HEADER))
1052
1055
          got_error=1;
1053
1056
          break;
1054
1057
        }
1055
 
        if (_mi_read_cache(&param->read_cache,(unsigned char*) to,block_info.filepos,
 
1058
        if (_mi_read_cache(&param->read_cache,(uchar*) to,block_info.filepos,
1056
1059
                           (uint) block_info.data_len,
1057
1060
                           flag == 1 ? READING_NEXT : 0))
1058
1061
          goto err;
1122
1125
      records++;
1123
1126
      if (param->testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0)
1124
1127
      {
1125
 
        printf("%s\r", llstr(records,llbuff)); fflush(stdout);
 
1128
        printf("%s\r", llstr(records,llbuff)); VOID(fflush(stdout));
1126
1129
      }
1127
1130
 
1128
1131
      /* Check if keys match the record */
1133
1136
        if (mi_is_key_active(info->s->state.key_map, key))
1134
1137
        {
1135
1138
          {
1136
 
            uint32_t key_length=_mi_make_key(info,key,info->lastkey,record,
 
1139
            uint key_length=_mi_make_key(info,key,info->lastkey,record,
1137
1140
                                         start_recpos);
1138
1141
            if (extend)
1139
1142
            {
1153
1156
              }
1154
1157
            }
1155
1158
            else
1156
 
              key_checksum[key]+=mi_byte_checksum((unsigned char*) info->lastkey,
 
1159
              key_checksum[key]+=mi_byte_checksum((uchar*) info->lastkey,
1157
1160
                                                  key_length);
1158
1161
          }
1159
1162
        }
1169
1172
  }
1170
1173
  if (param->testflag & T_WRITE_LOOP)
1171
1174
  {
1172
 
    fputs("          \r",stdout); fflush(stdout);
 
1175
    VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
1173
1176
  }
1174
1177
  if (records != info->state->records)
1175
1178
  {
1186
1189
  }
1187
1190
  else if (param->glob_crc != info->state->checksum &&
1188
1191
           (info->s->options &
1189
 
            (HA_OPTION_COMPRESS_RECORD)))
 
1192
            (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
1190
1193
  {
1191
1194
    mi_check_print_warning(param,
1192
1195
                           "Record checksum is not the same as checksum stored in the index file\n");
1262
1265
    printf("Lost space:   %12s    Linkdata:     %10s\n",
1263
1266
           llstr(empty,llbuff),llstr(link_used,llbuff2));
1264
1267
  }
1265
 
  free(mi_get_rec_buff_ptr(info, record));
 
1268
  my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
1266
1269
  return (error);
1267
1270
 err:
1268
 
  mi_check_print_error(param,"got error: %d when reading datafile at record: %s",errno, llstr(records,llbuff));
 
1271
  mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff));
1269
1272
 err2:
1270
 
  free(mi_get_rec_buff_ptr(info, record));
 
1273
  my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
1271
1274
  param->testflag|=T_RETRY_WITHOUT_QUICK;
1272
1275
  return(1);
1273
1276
} /* chk_data_link */
1313
1316
 
1314
1317
    However, there is an exception. Sometimes MySQL disables non-unique
1315
1318
    indexes when the table is empty (e.g. when copying a table in
1316
 
    drizzled::alter_table()). When enabling the non-unique indexes, they
 
1319
    mysql_alter_table()). When enabling the non-unique indexes, they
1317
1320
    are still empty. So there is no index block that can be lost. This
1318
1321
    optimization is implemented in this function.
1319
1322
 
1330
1333
{
1331
1334
  MYISAM_SHARE *share= info->s;
1332
1335
  MI_STATE_INFO *state= &share->state;
1333
 
  uint32_t i;
 
1336
  uint i;
1334
1337
  int error;
1335
1338
 
1336
1339
  /*
1362
1365
        Flush dirty blocks of this index file from key cache and remove
1363
1366
        all blocks of this index file from key cache.
1364
1367
      */
1365
 
      error= flush_key_blocks(share->getKeyCache(), share->kfile,
 
1368
      error= flush_key_blocks(share->key_cache, share->kfile,
1366
1369
                              FLUSH_FORCE_WRITE);
1367
1370
      goto end;
1368
1371
    }
1375
1378
  }
1376
1379
 
1377
1380
  /* Remove all key blocks of this index file from key cache. */
1378
 
  if ((error= flush_key_blocks(share->getKeyCache(), share->kfile,
 
1381
  if ((error= flush_key_blocks(share->key_cache, share->kfile,
1379
1382
                               FLUSH_IGNORE_CHANGED)))
1380
 
    goto end;
 
1383
    goto end; /* purecov: inspected */
1381
1384
 
1382
1385
  /* Clear index root block pointers. */
1383
1386
  for (i= 0; i < share->base.keys; i++)
1406
1409
  int error,got_error;
1407
1410
  ha_rows start_records,new_header_length;
1408
1411
  my_off_t del;
1409
 
  int new_file;
 
1412
  File new_file;
1410
1413
  MYISAM_SHARE *share=info->s;
1411
1414
  char llbuff[22],llbuff2[22];
1412
1415
  SORT_INFO sort_info;
1428
1431
  }
1429
1432
  param->testflag|=T_REP; /* for easy checking */
1430
1433
 
1431
 
  if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
 
1434
  if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1432
1435
    param->testflag|=T_CALC_CHECKSUM;
1433
1436
 
1434
1437
  if (!param->using_global_keycache)
1435
 
    assert(0);
 
1438
    VOID(init_key_cache(dflt_key_cache, param->key_cache_block_size,
 
1439
                        param->use_buffers, 0, 0));
1436
1440
 
1437
 
  if (param->read_cache.init_io_cache(info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
 
1441
  if (init_io_cache(&param->read_cache,info->dfile,
 
1442
                    (uint) param->read_buffer_length,
 
1443
                    READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
1438
1444
  {
1439
1445
    memset(&info->rec_cache, 0, sizeof(info->rec_cache));
1440
1446
    goto err;
1441
1447
  }
1442
 
  if (not rep_quick)
1443
 
  {
1444
 
    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)))
1445
 
    {
 
1448
  if (!rep_quick)
 
1449
    if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
 
1450
                      WRITE_CACHE, new_header_length, 1,
 
1451
                      MYF(MY_WME | MY_WAIT_IF_FULL)))
1446
1452
      goto err;
1447
 
    }
1448
 
  }
1449
1453
  info->opt_flag|=WRITE_CACHE_USED;
1450
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.record) ||
1451
 
      !mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.rec_buff))
 
1454
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
 
1455
      !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
1452
1456
  {
1453
1457
    mi_check_print_error(param, "Not enough memory for extra record");
1454
1458
    goto err;
1457
1461
  if (!rep_quick)
1458
1462
  {
1459
1463
    /* Get real path for data file */
1460
 
    if ((new_file=my_create(internal::fn_format(param->temp_filename,
1461
 
                                      share->data_file_name, "",
1462
 
                                      DATA_TMP_EXT, 2+4),
1463
 
                            0,param->tmpfile_createflag,
1464
 
                            MYF(0))) < 0)
 
1464
    if ((new_file=my_raid_create(fn_format(param->temp_filename,
 
1465
                                           share->data_file_name, "",
 
1466
                                           DATA_TMP_EXT, 2+4),
 
1467
                                 0,param->tmpfile_createflag,
 
1468
                                 share->base.raid_type,
 
1469
                                 share->base.raid_chunks,
 
1470
                                 share->base.raid_chunksize,
 
1471
                                 MYF(0))) < 0)
1465
1472
    {
1466
1473
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
1467
 
                           param->temp_filename);
 
1474
                           param->temp_filename);
1468
1475
      goto err;
1469
1476
    }
1470
1477
    if (new_header_length &&
1471
1478
        filecopy(param,new_file,info->dfile,0L,new_header_length,
1472
 
                 "datafile-header"))
 
1479
                 "datafile-header"))
1473
1480
      goto err;
1474
1481
    info->s->state.dellink= HA_OFFSET_ERROR;
1475
1482
    info->rec_cache.file=new_file;
1485
1492
  sort_param.pos=sort_param.max_pos=share->pack.header_length;
1486
1493
  sort_param.filepos=new_header_length;
1487
1494
  param->read_cache.end_of_file=sort_info.filelength=
1488
 
    lseek(info->dfile,0L,SEEK_END);
 
1495
    my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
1489
1496
  sort_info.dupp=0;
1490
1497
  sort_param.fix_datafile= (bool) (! rep_quick);
1491
1498
  sort_param.master=1;
1513
1520
  {
1514
1521
    if (writekeys(&sort_param))
1515
1522
    {
1516
 
      if (errno != HA_ERR_FOUND_DUPP_KEY)
 
1523
      if (my_errno != HA_ERR_FOUND_DUPP_KEY)
1517
1524
        goto err;
1518
1525
      mi_check_print_info(param,"Duplicate key %2d for record at %10s against new record at %10s",
1519
1526
                          info->errkey+1,
1521
1528
                          llstr(info->dupp_key_pos,llbuff2));
1522
1529
      if (param->testflag & T_VERBOSE)
1523
1530
      {
1524
 
        _mi_make_key(info,(uint) info->errkey,info->lastkey,
1525
 
                     sort_param.record,0L);
 
1531
        VOID(_mi_make_key(info,(uint) info->errkey,info->lastkey,
 
1532
                          sort_param.record,0L));
1526
1533
      }
1527
1534
      sort_info.dupp++;
1528
1535
      if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
1542
1549
 
1543
1550
  if (param->testflag & T_WRITE_LOOP)
1544
1551
  {
1545
 
    fputs("          \r",stdout); fflush(stdout);
 
1552
    VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
1546
1553
  }
1547
1554
  if (ftruncate(share->kfile, info->state->key_file_length))
1548
1555
  {
1549
1556
    mi_check_print_warning(param,
1550
1557
                           "Can't change size of indexfile, error: %d",
1551
 
                           errno);
 
1558
                           my_errno);
1552
1559
    goto err;
1553
1560
  }
1554
1561
 
1574
1581
 
1575
1582
  if (!rep_quick)
1576
1583
  {
1577
 
    internal::my_close(info->dfile,MYF(0));
 
1584
    my_close(info->dfile,MYF(0));
1578
1585
    info->dfile=new_file;
1579
1586
    info->state->data_file_length=sort_param.filepos;
1580
1587
    share->state.version=(ulong) time((time_t*) 0);     /* Force reopen */
1607
1614
    /* Replace the actual file with the temporary file */
1608
1615
    if (new_file >= 0)
1609
1616
    {
1610
 
      internal::my_close(new_file,MYF(0));
 
1617
      my_close(new_file,MYF(0));
1611
1618
      info->dfile=new_file= -1;
1612
1619
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
1613
1620
                            DATA_TMP_EXT, share->base.raid_chunks,
1620
1627
  if (got_error)
1621
1628
  {
1622
1629
    if (! param->error_printed)
1623
 
      mi_check_print_error(param,"%d for record at pos %s",errno,
 
1630
      mi_check_print_error(param,"%d for record at pos %s",my_errno,
1624
1631
                  llstr(sort_param.start_recpos,llbuff));
1625
1632
    if (new_file >= 0)
1626
1633
    {
1627
 
      internal::my_close(new_file,MYF(0));
1628
 
      my_delete(param->temp_filename, MYF(MY_WME));
 
1634
      VOID(my_close(new_file,MYF(0)));
 
1635
      VOID(my_raid_delete(param->temp_filename,info->s->base.raid_chunks,
 
1636
                          MYF(MY_WME)));
1629
1637
      info->rec_cache.file=-1; /* don't flush data to new_file, it's closed */
1630
1638
    }
1631
1639
    mi_mark_crashed_on_repair(info);
1632
1640
  }
1633
 
 
1634
 
  void * rec_buff_ptr= NULL;
1635
 
  rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.rec_buff);
1636
 
  if (rec_buff_ptr != NULL)
1637
 
    free(rec_buff_ptr);
1638
 
  rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1639
 
  if (rec_buff_ptr != NULL)
1640
 
    free(rec_buff_ptr);
1641
 
  rec_buff_ptr= NULL;
1642
 
 
1643
 
  free(sort_info.buff);
1644
 
  param->read_cache.end_io_cache();
 
1641
  my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff),
 
1642
                            MYF(MY_ALLOW_ZERO_PTR));
 
1643
  my_free(mi_get_rec_buff_ptr(info, sort_param.record),
 
1644
          MYF(MY_ALLOW_ZERO_PTR));
 
1645
  my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
 
1646
  VOID(end_io_cache(&param->read_cache));
1645
1647
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1646
 
  info->rec_cache.end_io_cache();
1647
 
  got_error|= flush_blocks(param, share->getKeyCache(), share->kfile);
1648
 
  if (not got_error && param->testflag & T_UNPACK)
 
1648
  VOID(end_io_cache(&info->rec_cache));
 
1649
  got_error|=flush_blocks(param, share->key_cache, share->kfile);
 
1650
  if (!got_error && param->testflag & T_UNPACK)
1649
1651
  {
1650
 
    share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
 
1652
    share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
1651
1653
    share->pack.header_length=0;
1652
1654
    share->data_file_type=sort_info.new_data_file_type;
1653
1655
  }
1661
1663
 
1662
1664
static int writekeys(MI_SORT_PARAM *sort_param)
1663
1665
{
1664
 
  register uint32_t i;
1665
 
  unsigned char    *key;
 
1666
  register uint i;
 
1667
  uchar    *key;
1666
1668
  MI_INFO  *info=   sort_param->sort_info->info;
1667
 
  unsigned char    *buff=   sort_param->record;
 
1669
  uchar    *buff=   sort_param->record;
1668
1670
  my_off_t filepos= sort_param->filepos;
1669
1671
 
1670
1672
  key=info->lastkey+info->s->base.max_key_length;
1673
1675
    if (mi_is_key_active(info->s->state.key_map, i))
1674
1676
    {
1675
1677
      {
1676
 
        uint32_t key_length=_mi_make_key(info,i,key,buff,filepos);
 
1678
        uint key_length=_mi_make_key(info,i,key,buff,filepos);
1677
1679
        if (_mi_ck_write(info,i,key,key_length))
1678
1680
          goto err;
1679
1681
      }
1682
1684
  return(0);
1683
1685
 
1684
1686
 err:
1685
 
  if (errno == HA_ERR_FOUND_DUPP_KEY)
 
1687
  if (my_errno == HA_ERR_FOUND_DUPP_KEY)
1686
1688
  {
1687
1689
    info->errkey=(int) i;                       /* This key was found */
1688
1690
    while ( i-- > 0 )
1690
1692
      if (mi_is_key_active(info->s->state.key_map, i))
1691
1693
      {
1692
1694
        {
1693
 
          uint32_t key_length=_mi_make_key(info,i,key,buff,filepos);
 
1695
          uint key_length=_mi_make_key(info,i,key,buff,filepos);
1694
1696
          if (_mi_ck_delete(info,i,key,key_length))
1695
1697
            break;
1696
1698
        }
1706
1708
 
1707
1709
        /* Change all key-pointers that points to a records */
1708
1710
 
1709
 
int movepoint(register MI_INFO *info, unsigned char *record, my_off_t oldpos,
1710
 
              my_off_t newpos, uint32_t prot_key)
 
1711
int movepoint(register MI_INFO *info, uchar *record, my_off_t oldpos,
 
1712
              my_off_t newpos, uint prot_key)
1711
1713
{
1712
 
  register uint32_t i;
1713
 
  unsigned char *key;
1714
 
  uint32_t key_length;
 
1714
  register uint i;
 
1715
  uchar *key;
 
1716
  uint key_length;
1715
1717
 
1716
1718
  key=info->lastkey+info->s->base.max_key_length;
1717
1719
  for (i=0 ; i < info->s->base.keys; i++)
1721
1723
      key_length=_mi_make_key(info,i,key,record,oldpos);
1722
1724
      if (info->s->keyinfo[i].flag & HA_NOSAME)
1723
1725
      {                                 /* Change pointer direct */
1724
 
        uint32_t nod_flag;
 
1726
        uint nod_flag;
1725
1727
        MI_KEYDEF *keyinfo;
1726
1728
        keyinfo=info->s->keyinfo+i;
1727
1729
        if (_mi_search(info,keyinfo,key,USE_WHOLE_KEY,
1751
1753
 
1752
1754
        /* Tell system that we want all memory for our cache */
1753
1755
 
1754
 
void lock_memory(MI_CHECK *)
 
1756
void lock_memory(MI_CHECK *param __attribute__((unused)))
1755
1757
{
 
1758
#ifdef SUN_OS                           /* Key-cacheing thrases on sun 4.1 */
 
1759
  if (param->opt_lock_memory)
 
1760
  {
 
1761
    int success = mlockall(MCL_CURRENT);        /* or plock(DATLOCK); */
 
1762
    if (geteuid() == 0 && success != 0)
 
1763
      mi_check_print_warning(param,
 
1764
                             "Failed to lock memory. errno %d",my_errno);
 
1765
  }
 
1766
#endif
1756
1767
} /* lock_memory */
1757
1768
 
1758
1769
 
1759
1770
        /* Flush all changed blocks to disk */
1760
1771
 
1761
 
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, int file)
 
1772
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file)
1762
1773
{
1763
1774
  if (flush_key_blocks(key_cache, file, FLUSH_RELEASE))
1764
1775
  {
1765
 
    mi_check_print_error(param,"%d when trying to write bufferts",errno);
 
1776
    mi_check_print_error(param,"%d when trying to write bufferts",my_errno);
1766
1777
    return(1);
1767
1778
  }
1768
1779
  if (!param->using_global_keycache)
1775
1786
 
1776
1787
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
1777
1788
{
1778
 
  register uint32_t key;
 
1789
  register uint key;
1779
1790
  register MI_KEYDEF *keyinfo;
1780
 
  int new_file;
 
1791
  File new_file;
1781
1792
  my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
1782
 
  uint32_t r_locks,w_locks;
 
1793
  uint r_locks,w_locks;
1783
1794
  int old_lock;
1784
1795
  MYISAM_SHARE *share=info->s;
1785
1796
  MI_STATE_INFO old_state;
1792
1803
    printf("- Sorting index for MyISAM-table '%s'\n",name);
1793
1804
 
1794
1805
  /* Get real path for index file */
1795
 
  internal::fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32);
1796
 
  if ((new_file=my_create(internal::fn_format(param->temp_filename,param->temp_filename,
 
1806
  fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32);
 
1807
  if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename,
1797
1808
                                    "", INDEX_TMP_EXT,2+4),
1798
1809
                          0,param->tmpfile_createflag,MYF(0))) <= 0)
1799
1810
  {
1824
1835
  }
1825
1836
 
1826
1837
  /* Flush key cache for this file if we are calling this outside myisamchk */
1827
 
  flush_key_blocks(share->getKeyCache(), share->kfile, FLUSH_IGNORE_CHANGED);
 
1838
  flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED);
1828
1839
 
1829
1840
  share->state.version=(ulong) time((time_t*) 0);
1830
1841
  old_state= share->state;                      /* save state if not stored */
1835
1846
        /* Put same locks as old file */
1836
1847
  share->r_locks= share->w_locks= share->tot_locks= 0;
1837
1848
  (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
1838
 
  internal::my_close(share->kfile,MYF(MY_WME));
 
1849
  VOID(my_close(share->kfile,MYF(MY_WME)));
1839
1850
  share->kfile = -1;
1840
 
  internal::my_close(new_file,MYF(MY_WME));
 
1851
  VOID(my_close(new_file,MYF(MY_WME)));
1841
1852
  if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1842
1853
                        MYF(0)) ||
1843
1854
      mi_open_keyfile(share))
1861
1872
  return(0);
1862
1873
 
1863
1874
err:
1864
 
  internal::my_close(new_file,MYF(MY_WME));
 
1875
  VOID(my_close(new_file,MYF(MY_WME)));
1865
1876
err2:
1866
 
  my_delete(param->temp_filename,MYF(MY_WME));
 
1877
  VOID(my_delete(param->temp_filename,MYF(MY_WME)));
1867
1878
  return(-1);
1868
1879
} /* mi_sort_index */
1869
1880
 
1871
1882
         /* Sort records recursive using one index */
1872
1883
 
1873
1884
static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
1874
 
                          my_off_t pagepos, int new_file)
 
1885
                          my_off_t pagepos, File new_file)
1875
1886
{
1876
 
  uint32_t length,nod_flag,used_length, key_length;
1877
 
  unsigned char *buff,*keypos,*endpos;
1878
 
  unsigned char key[HA_MAX_POSSIBLE_KEY_BUFF];
 
1887
  uint length,nod_flag,used_length, key_length;
 
1888
  uchar *buff,*keypos,*endpos;
 
1889
  uchar key[HA_MAX_POSSIBLE_KEY_BUFF];
1879
1890
  my_off_t new_page_pos,next_page;
1880
1891
  char llbuff[22];
1881
1892
 
1882
1893
  new_page_pos=param->new_file_pos;
1883
1894
  param->new_file_pos+=keyinfo->block_length;
1884
1895
 
1885
 
  if (!(buff=(unsigned char*) malloc(keyinfo->block_length)))
 
1896
  if (!(buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1886
1897
  {
1887
1898
    mi_check_print_error(param,"Not enough memory for key block");
1888
1899
    return(-1);
1919
1930
  /* Fill block with zero and write it to the new index file */
1920
1931
  length=mi_getint(buff);
1921
1932
  memset(buff+length, 0, keyinfo->block_length-length);
1922
 
  if (my_pwrite(new_file,(unsigned char*) buff,(uint) keyinfo->block_length,
 
1933
  if (my_pwrite(new_file,(uchar*) buff,(uint) keyinfo->block_length,
1923
1934
                new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
1924
1935
  {
1925
 
    mi_check_print_error(param,"Can't write indexblock, error: %d",errno);
 
1936
    mi_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
1926
1937
    goto err;
1927
1938
  }
1928
 
  free(buff);
 
1939
  my_afree((uchar*) buff);
1929
1940
  return(0);
1930
1941
err:
1931
 
  free(buff);
 
1942
  my_afree((uchar*) buff);
1932
1943
  return(1);
1933
1944
} /* sort_one_index */
1934
1945
 
1944
1955
 
1945
1956
int change_to_newfile(const char * filename, const char * old_ext,
1946
1957
                      const char * new_ext,
1947
 
                      uint32_t raid_chunks,
 
1958
                      uint raid_chunks __attribute__((unused)),
1948
1959
                      myf MyFlags)
1949
1960
{
1950
 
  (void)raid_chunks;
1951
1961
  char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
1952
1962
  /* Get real path to filename */
1953
 
  (void) internal::fn_format(old_filename,filename,"",old_ext,2+4+32);
 
1963
  (void) fn_format(old_filename,filename,"",old_ext,2+4+32);
1954
1964
  return my_redel(old_filename,
1955
 
                  internal::fn_format(new_filename,old_filename,"",new_ext,2+4),
 
1965
                  fn_format(new_filename,old_filename,"",new_ext,2+4),
1956
1966
                  MYF(MY_WME | MY_LINK_WARNING | MyFlags));
1957
1967
} /* change_to_newfile */
1958
1968
 
1960
1970
 
1961
1971
        /* Copy a block between two files */
1962
1972
 
1963
 
int filecopy(MI_CHECK *param, int to,int from,my_off_t start,
 
1973
int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
1964
1974
             my_off_t length, const char *type)
1965
1975
{
1966
1976
  char tmp_buff[IO_SIZE],*buff;
1967
1977
  ulong buff_length;
1968
1978
 
1969
 
  buff_length=(ulong) min(param->write_buffer_length, (size_t)length);
1970
 
  if (!(buff=(char *)malloc(buff_length)))
 
1979
  buff_length=(ulong) min(param->write_buffer_length,length);
 
1980
  if (!(buff=my_malloc(buff_length,MYF(0))))
1971
1981
  {
1972
1982
    buff=tmp_buff; buff_length=IO_SIZE;
1973
1983
  }
1974
1984
 
1975
 
  lseek(from,start,SEEK_SET);
 
1985
  VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
1976
1986
  while (length > buff_length)
1977
1987
  {
1978
 
    if (my_read(from,(unsigned char*) buff,buff_length,MYF(MY_NABP)) ||
1979
 
        my_write(to,(unsigned char*) buff,buff_length,param->myf_rw))
 
1988
    if (my_read(from,(uchar*) buff,buff_length,MYF(MY_NABP)) ||
 
1989
        my_write(to,(uchar*) buff,buff_length,param->myf_rw))
1980
1990
      goto err;
1981
1991
    length-= buff_length;
1982
1992
  }
1983
 
  if (my_read(from,(unsigned char*) buff,(uint) length,MYF(MY_NABP)) ||
1984
 
      my_write(to,(unsigned char*) buff,(uint) length,param->myf_rw))
 
1993
  if (my_read(from,(uchar*) buff,(uint) length,MYF(MY_NABP)) ||
 
1994
      my_write(to,(uchar*) buff,(uint) length,param->myf_rw))
1985
1995
    goto err;
1986
1996
  if (buff != tmp_buff)
1987
 
    free(buff);
 
1997
    my_free(buff,MYF(0));
1988
1998
  return(0);
1989
1999
err:
1990
2000
  if (buff != tmp_buff)
1991
 
    free(buff);
 
2001
    my_free(buff,MYF(0));
1992
2002
  mi_check_print_error(param,"Can't copy %s to tempfile, error %d",
1993
 
                       type,errno);
 
2003
                       type,my_errno);
1994
2004
  return(1);
1995
2005
}
1996
2006
 
2014
2024
                      const char * name, int rep_quick)
2015
2025
{
2016
2026
  int got_error;
2017
 
  uint32_t i;
 
2027
  uint i;
2018
2028
  ulong length;
2019
2029
  ha_rows start_records;
2020
2030
  my_off_t new_header_length,del;
2021
 
  int new_file;
 
2031
  File new_file;
2022
2032
  MI_SORT_PARAM sort_param;
2023
2033
  MYISAM_SHARE *share=info->s;
2024
2034
  HA_KEYSEG *keyseg;
2039
2049
  }
2040
2050
  param->testflag|=T_REP; /* for easy checking */
2041
2051
 
2042
 
  if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
 
2052
  if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
2043
2053
    param->testflag|=T_CALC_CHECKSUM;
2044
2054
 
2045
2055
  memset(&sort_info, 0, sizeof(sort_info));
2046
2056
  memset(&sort_param, 0, sizeof(sort_param));
2047
2057
  if (!(sort_info.key_block=
2048
 
        alloc_key_blocks(param, (uint) param->sort_key_blocks, share->base.max_key_block_length))
2049
 
      || param->read_cache.init_io_cache(info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME))
2050
 
      || (! 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)))
2051
 
  {
 
2058
        alloc_key_blocks(param,
 
2059
                         (uint) param->sort_key_blocks,
 
2060
                         share->base.max_key_block_length))
 
2061
      || init_io_cache(&param->read_cache,info->dfile,
 
2062
                       (uint) param->read_buffer_length,
 
2063
                       READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
 
2064
      (! rep_quick &&
 
2065
       init_io_cache(&info->rec_cache,info->dfile,
 
2066
                     (uint) param->write_buffer_length,
 
2067
                     WRITE_CACHE,new_header_length,1,
 
2068
                     MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)))
2052
2069
    goto err;
2053
 
  }
2054
2070
  sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
2055
2071
  info->opt_flag|=WRITE_CACHE_USED;
2056
2072
  info->rec_cache.file=info->dfile;             /* for sort_delete_record */
2057
2073
 
2058
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.record) ||
2059
 
      !mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.rec_buff))
 
2074
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
 
2075
      !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
2060
2076
  {
2061
2077
    mi_check_print_error(param, "Not enough memory for extra record");
2062
2078
    goto err;
2064
2080
  if (!rep_quick)
2065
2081
  {
2066
2082
    /* Get real path for data file */
2067
 
    if ((new_file=my_create(internal::fn_format(param->temp_filename,
2068
 
                                      share->data_file_name, "",
2069
 
                                      DATA_TMP_EXT, 2+4),
2070
 
                            0,param->tmpfile_createflag,
2071
 
                            MYF(0))) < 0)
 
2083
    if ((new_file=my_raid_create(fn_format(param->temp_filename,
 
2084
                                           share->data_file_name, "",
 
2085
                                           DATA_TMP_EXT, 2+4),
 
2086
                                 0,param->tmpfile_createflag,
 
2087
                                 share->base.raid_type,
 
2088
                                 share->base.raid_chunks,
 
2089
                                 share->base.raid_chunksize,
 
2090
                                 MYF(0))) < 0)
2072
2091
    {
2073
2092
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
2074
 
                           param->temp_filename);
 
2093
                           param->temp_filename);
2075
2094
      goto err;
2076
2095
    }
2077
2096
    if (new_header_length &&
2106
2125
  sort_info.dupp=0;
2107
2126
  sort_info.buff=0;
2108
2127
  param->read_cache.end_of_file=sort_info.filelength=
2109
 
    lseek(param->read_cache.file,0L,SEEK_END);
 
2128
    my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
2110
2129
 
2111
2130
  sort_param.wordlist=NULL;
2112
2131
 
2121
2140
     (ha_rows) (sort_info.filelength/length+1));
2122
2141
  sort_param.key_cmp=sort_key_cmp;
2123
2142
  sort_param.lock_in_memory=lock_memory;
 
2143
  sort_param.tmpdir=param->tmpdir;
2124
2144
  sort_param.sort_info=&sort_info;
2125
2145
  sort_param.fix_datafile= (bool) (! rep_quick);
2126
2146
  sort_param.master =1;
2127
 
 
 
2147
  
2128
2148
  del=info->state->del;
2129
2149
  param->glob_crc=0;
2130
2150
  if (param->testflag & T_CALC_CHECKSUM)
2185
2205
    }
2186
2206
    /* No need to calculate checksum again. */
2187
2207
    sort_param.calc_checksum= 0;
2188
 
    sort_param.wordroot.free_root(MYF(0));
 
2208
    free_root(&sort_param.wordroot, MYF(0));
2189
2209
 
2190
2210
    /* Set for next loop */
2191
2211
    sort_info.max_records= (ha_rows) info->state->records;
2201
2221
    if (sort_param.fix_datafile)
2202
2222
    {
2203
2223
      param->read_cache.end_of_file=sort_param.filepos;
2204
 
      if (write_data_suffix(&sort_info, 1) || info->rec_cache.end_io_cache())
2205
 
      {
 
2224
      if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
2206
2225
        goto err;
2207
 
      }
2208
2226
      if (param->testflag & T_SAFE_REPAIR)
2209
2227
      {
2210
2228
        /* Don't repair if we loosed more than one row */
2218
2236
        sort_param.filepos;
2219
2237
      /* Only whole records */
2220
2238
      share->state.version=(ulong) time((time_t*) 0);
2221
 
      internal::my_close(info->dfile,MYF(0));
 
2239
      my_close(info->dfile,MYF(0));
2222
2240
      info->dfile=new_file;
2223
2241
      share->data_file_type=sort_info.new_data_file_type;
2224
2242
      share->pack.header_length=(ulong) new_header_length;
2228
2246
      info->state->data_file_length=sort_param.max_pos;
2229
2247
 
2230
2248
    param->read_cache.file=info->dfile;         /* re-init read cache */
2231
 
    param->read_cache.reinit_io_cache(READ_CACHE,share->pack.header_length, 1,1);
 
2249
    reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
 
2250
                    1,1);
2232
2251
  }
2233
2252
 
2234
2253
  if (param->testflag & T_WRITE_LOOP)
2235
2254
  {
2236
 
    fputs("          \r",stdout); fflush(stdout);
 
2255
    VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
2237
2256
  }
2238
2257
 
2239
2258
  if (rep_quick && del+sort_info.dupp != info->state->del)
2260
2279
      if (ftruncate(info->dfile, skr))
2261
2280
        mi_check_print_warning(param,
2262
2281
                               "Can't change size of datafile,  error: %d",
2263
 
                               errno);
 
2282
                               my_errno);
2264
2283
  }
2265
2284
  if (param->testflag & T_CALC_CHECKSUM)
2266
2285
    info->state->checksum=param->glob_crc;
2268
2287
  if (ftruncate(share->kfile, info->state->key_file_length))
2269
2288
    mi_check_print_warning(param,
2270
2289
                           "Can't change size of indexfile, error: %d",
2271
 
                           errno);
 
2290
                           my_errno);
2272
2291
 
2273
2292
  if (!(param->testflag & T_SILENT))
2274
2293
  {
2285
2304
    memcpy( &share->state.state, info->state, sizeof(*info->state));
2286
2305
 
2287
2306
err:
2288
 
  got_error|= flush_blocks(param, share->getKeyCache(), share->kfile);
2289
 
  info->rec_cache.end_io_cache();
2290
 
  if (!got_error)
2291
 
  {
2292
 
    /* Replace the actual file with the temporary file */
2293
 
    if (new_file >= 0)
2294
 
    {
2295
 
      internal::my_close(new_file,MYF(0));
2296
 
      info->dfile=new_file= -1;
2297
 
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
2298
 
                            DATA_TMP_EXT, share->base.raid_chunks,
2299
 
                            (param->testflag & T_BACKUP_DATA ?
2300
 
                             MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
2301
 
          mi_open_datafile(info,share,-1))
2302
 
        got_error=1;
2303
 
    }
2304
 
  }
2305
 
  if (got_error)
2306
 
  {
2307
 
    if (! param->error_printed)
2308
 
      mi_check_print_error(param,"%d when fixing table",errno);
2309
 
    if (new_file >= 0)
2310
 
    {
2311
 
      internal::my_close(new_file,MYF(0));
2312
 
      my_delete(param->temp_filename, MYF(MY_WME));
2313
 
      if (info->dfile == new_file)
2314
 
        info->dfile= -1;
2315
 
    }
2316
 
    mi_mark_crashed_on_repair(info);
2317
 
  }
2318
 
  else if (key_map == share->state.key_map)
2319
 
    share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
2320
 
  share->state.changed|=STATE_NOT_SORTED_PAGES;
2321
 
 
2322
 
  void * rec_buff_ptr= NULL;
2323
 
  rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.rec_buff);
2324
 
  if (rec_buff_ptr != NULL)
2325
 
    free(rec_buff_ptr);
2326
 
  rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
2327
 
  if (rec_buff_ptr != NULL)
2328
 
    free(rec_buff_ptr);
2329
 
  rec_buff_ptr= NULL;
2330
 
 
2331
 
  free((unsigned char*) sort_info.key_block);
2332
 
  free(sort_info.buff);
2333
 
  param->read_cache.end_io_cache();
2334
 
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
2335
 
  if (!got_error && (param->testflag & T_UNPACK))
2336
 
  {
2337
 
    share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
 
2307
  got_error|= flush_blocks(param, share->key_cache, share->kfile);
 
2308
  VOID(end_io_cache(&info->rec_cache));
 
2309
  if (!got_error)
 
2310
  {
 
2311
    /* Replace the actual file with the temporary file */
 
2312
    if (new_file >= 0)
 
2313
    {
 
2314
      my_close(new_file,MYF(0));
 
2315
      info->dfile=new_file= -1;
 
2316
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
 
2317
                            DATA_TMP_EXT, share->base.raid_chunks,
 
2318
                            (param->testflag & T_BACKUP_DATA ?
 
2319
                             MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
 
2320
          mi_open_datafile(info,share,-1))
 
2321
        got_error=1;
 
2322
    }
 
2323
  }
 
2324
  if (got_error)
 
2325
  {
 
2326
    if (! param->error_printed)
 
2327
      mi_check_print_error(param,"%d when fixing table",my_errno);
 
2328
    if (new_file >= 0)
 
2329
    {
 
2330
      VOID(my_close(new_file,MYF(0)));
 
2331
      VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks,
 
2332
                          MYF(MY_WME)));
 
2333
      if (info->dfile == new_file)
 
2334
        info->dfile= -1;
 
2335
    }
 
2336
    mi_mark_crashed_on_repair(info);
 
2337
  }
 
2338
  else if (key_map == share->state.key_map)
 
2339
    share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
 
2340
  share->state.changed|=STATE_NOT_SORTED_PAGES;
 
2341
 
 
2342
  my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff),
 
2343
                            MYF(MY_ALLOW_ZERO_PTR));
 
2344
  my_free(mi_get_rec_buff_ptr(info, sort_param.record),
 
2345
          MYF(MY_ALLOW_ZERO_PTR));
 
2346
  my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
 
2347
  my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
 
2348
  VOID(end_io_cache(&param->read_cache));
 
2349
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
 
2350
  if (!got_error && (param->testflag & T_UNPACK))
 
2351
  {
 
2352
    share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
 
2353
    share->pack.header_length=0;
 
2354
  }
 
2355
  return(got_error);
 
2356
}
 
2357
 
 
2358
/*
 
2359
  Threaded repair of table using sorting
 
2360
 
 
2361
  SYNOPSIS
 
2362
    mi_repair_parallel()
 
2363
    param               Repair parameters
 
2364
    info                MyISAM handler to repair
 
2365
    name                Name of table (for warnings)
 
2366
    rep_quick           set to <> 0 if we should not change data file
 
2367
 
 
2368
  DESCRIPTION
 
2369
    Same as mi_repair_by_sort but do it multithreaded
 
2370
    Each key is handled by a separate thread.
 
2371
    TODO: make a number of threads a parameter
 
2372
 
 
2373
    In parallel repair we use one thread per index. There are two modes:
 
2374
 
 
2375
    Quick
 
2376
 
 
2377
      Only the indexes are rebuilt. All threads share a read buffer.
 
2378
      Every thread that needs fresh data in the buffer enters the shared
 
2379
      cache lock. The last thread joining the lock reads the buffer from
 
2380
      the data file and wakes all other threads.
 
2381
 
 
2382
    Non-quick
 
2383
 
 
2384
      The data file is rebuilt and all indexes are rebuilt to point to
 
2385
      the new record positions. One thread is the master thread. It
 
2386
      reads from the old data file and writes to the new data file. It
 
2387
      also creates one of the indexes. The other threads read from a
 
2388
      buffer which is filled by the master. If they need fresh data,
 
2389
      they enter the shared cache lock. If the masters write buffer is
 
2390
      full, it flushes it to the new data file and enters the shared
 
2391
      cache lock too. When all threads joined in the lock, the master
 
2392
      copies its write buffer to the read buffer for the other threads
 
2393
      and wakes them.
 
2394
 
 
2395
  RESULT
 
2396
    0   ok
 
2397
    <>0 Error
 
2398
*/
 
2399
 
 
2400
int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
 
2401
                        const char * name, int rep_quick)
 
2402
{
 
2403
  int got_error;
 
2404
  uint i,key, total_key_length, istep;
 
2405
  ulong rec_length;
 
2406
  ha_rows start_records;
 
2407
  my_off_t new_header_length,del;
 
2408
  File new_file;
 
2409
  MI_SORT_PARAM *sort_param=0;
 
2410
  MYISAM_SHARE *share=info->s;
 
2411
  ulong   *rec_per_key_part;
 
2412
  HA_KEYSEG *keyseg;
 
2413
  char llbuff[22];
 
2414
  IO_CACHE new_data_cache; /* For non-quick repair. */
 
2415
  IO_CACHE_SHARE io_share;
 
2416
  SORT_INFO sort_info;
 
2417
  uint64_t key_map= 0;
 
2418
  pthread_attr_t thr_attr;
 
2419
  ulong max_pack_reclength;
 
2420
 
 
2421
  start_records=info->state->records;
 
2422
  got_error=1;
 
2423
  new_file= -1;
 
2424
  new_header_length=(param->testflag & T_UNPACK) ? 0 :
 
2425
    share->pack.header_length;
 
2426
  if (!(param->testflag & T_SILENT))
 
2427
  {
 
2428
    printf("- parallel recovering (with sort) MyISAM-table '%s'\n",name);
 
2429
    printf("Data records: %s\n", llstr(start_records,llbuff));
 
2430
  }
 
2431
  param->testflag|=T_REP; /* for easy checking */
 
2432
 
 
2433
  if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
 
2434
    param->testflag|=T_CALC_CHECKSUM;
 
2435
 
 
2436
  /*
 
2437
    Quick repair (not touching data file, rebuilding indexes):
 
2438
    {
 
2439
      Read  cache is (MI_CHECK *param)->read_cache using info->dfile.
 
2440
    }
 
2441
 
 
2442
    Non-quick repair (rebuilding data file and indexes):
 
2443
    {
 
2444
      Master thread:
 
2445
 
 
2446
        Read  cache is (MI_CHECK *param)->read_cache using info->dfile.
 
2447
        Write cache is (MI_INFO   *info)->rec_cache  using new_file.
 
2448
 
 
2449
      Slave threads:
 
2450
 
 
2451
        Read  cache is new_data_cache synced to master rec_cache.
 
2452
 
 
2453
      The final assignment of the filedescriptor for rec_cache is done
 
2454
      after the cache creation.
 
2455
 
 
2456
      Don't check file size on new_data_cache, as the resulting file size
 
2457
      is not known yet.
 
2458
 
 
2459
      As rec_cache and new_data_cache are synced, write_buffer_length is
 
2460
      used for the read cache 'new_data_cache'. Both start at the same
 
2461
      position 'new_header_length'.
 
2462
    }
 
2463
  */
 
2464
  memset(&sort_info, 0, sizeof(sort_info));
 
2465
  /* Initialize pthread structures before goto err. */
 
2466
  pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
 
2467
  pthread_cond_init(&sort_info.cond, 0);
 
2468
 
 
2469
  if (!(sort_info.key_block=
 
2470
        alloc_key_blocks(param, (uint) param->sort_key_blocks,
 
2471
                         share->base.max_key_block_length)) ||
 
2472
      init_io_cache(&param->read_cache, info->dfile,
 
2473
                    (uint) param->read_buffer_length,
 
2474
                    READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) ||
 
2475
      (!rep_quick &&
 
2476
       (init_io_cache(&info->rec_cache, info->dfile,
 
2477
                      (uint) param->write_buffer_length,
 
2478
                      WRITE_CACHE, new_header_length, 1,
 
2479
                      MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) ||
 
2480
        init_io_cache(&new_data_cache, -1,
 
2481
                      (uint) param->write_buffer_length,
 
2482
                      READ_CACHE, new_header_length, 1,
 
2483
                      MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))))
 
2484
    goto err;
 
2485
  sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
 
2486
  info->opt_flag|=WRITE_CACHE_USED;
 
2487
  info->rec_cache.file=info->dfile;         /* for sort_delete_record */
 
2488
 
 
2489
  if (!rep_quick)
 
2490
  {
 
2491
    /* Get real path for data file */
 
2492
    if ((new_file=my_raid_create(fn_format(param->temp_filename,
 
2493
                                           share->data_file_name, "",
 
2494
                                           DATA_TMP_EXT,
 
2495
                                           2+4),
 
2496
                                 0,param->tmpfile_createflag,
 
2497
                                 share->base.raid_type,
 
2498
                                 share->base.raid_chunks,
 
2499
                                 share->base.raid_chunksize,
 
2500
                                 MYF(0))) < 0)
 
2501
    {
 
2502
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
 
2503
                           param->temp_filename);
 
2504
      goto err;
 
2505
    }
 
2506
    if (new_header_length &&
 
2507
        filecopy(param, new_file,info->dfile,0L,new_header_length,
 
2508
                 "datafile-header"))
 
2509
      goto err;
 
2510
    if (param->testflag & T_UNPACK)
 
2511
    {
 
2512
      share->options&= ~HA_OPTION_COMPRESS_RECORD;
 
2513
      mi_int2store(share->state.header.options,share->options);
 
2514
    }
 
2515
    share->state.dellink= HA_OFFSET_ERROR;
 
2516
    info->rec_cache.file=new_file;
 
2517
  }
 
2518
 
 
2519
  info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
 
2520
 
 
2521
  /* Optionally drop indexes and optionally modify the key_map. */
 
2522
  mi_drop_all_indexes(param, info, false);
 
2523
  key_map= share->state.key_map;
 
2524
  if (param->testflag & T_CREATE_MISSING_KEYS)
 
2525
  {
 
2526
    /* Invert the copied key_map to recreate all disabled indexes. */
 
2527
    key_map= ~key_map;
 
2528
  }
 
2529
 
 
2530
  sort_info.info=info;
 
2531
  sort_info.param = param;
 
2532
 
 
2533
  set_data_file_type(&sort_info, share);
 
2534
  sort_info.dupp=0;
 
2535
  sort_info.buff=0;
 
2536
  param->read_cache.end_of_file=sort_info.filelength=
 
2537
    my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
 
2538
 
 
2539
  if (share->data_file_type == DYNAMIC_RECORD)
 
2540
    rec_length=max(share->base.min_pack_length+1,share->base.min_block_length);
 
2541
  else if (share->data_file_type == COMPRESSED_RECORD)
 
2542
    rec_length=share->base.min_block_length;
 
2543
  else
 
2544
    rec_length=share->base.pack_reclength;
 
2545
  /*
 
2546
    +1 below is required hack for parallel repair mode.
 
2547
    The info->state->records value, that is compared later
 
2548
    to sort_info.max_records and cannot exceed it, is
 
2549
    increased in sort_key_write. In mi_repair_by_sort, sort_key_write
 
2550
    is called after sort_key_read, where the comparison is performed,
 
2551
    but in parallel mode master thread can call sort_key_write
 
2552
    before some other repair thread calls sort_key_read.
 
2553
    Furthermore I'm not even sure +1 would be enough.
 
2554
    May be sort_info.max_records shold be always set to max value in
 
2555
    parallel mode.
 
2556
  */
 
2557
  sort_info.max_records=
 
2558
    ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records + 1:
 
2559
     (ha_rows) (sort_info.filelength/rec_length+1));
 
2560
 
 
2561
  del=info->state->del;
 
2562
  param->glob_crc=0;
 
2563
  /* for compressed tables */
 
2564
  max_pack_reclength= share->base.pack_reclength;
 
2565
  if (share->options & HA_OPTION_COMPRESS_RECORD)
 
2566
    set_if_bigger(max_pack_reclength, share->max_pack_length);
 
2567
  if (!(sort_param=(MI_SORT_PARAM *)
 
2568
        my_malloc((uint) share->base.keys *
 
2569
                  (sizeof(MI_SORT_PARAM) + max_pack_reclength),
 
2570
                  MYF(MY_ZEROFILL))))
 
2571
  {
 
2572
    mi_check_print_error(param,"Not enough memory for key!");
 
2573
    goto err;
 
2574
  }
 
2575
  total_key_length=0;
 
2576
  rec_per_key_part= param->rec_per_key_part;
 
2577
  info->state->records=info->state->del=share->state.split=0;
 
2578
  info->state->empty=0;
 
2579
 
 
2580
  for (i=key=0, istep=1 ; key < share->base.keys ;
 
2581
       rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
 
2582
  {
 
2583
    sort_param[i].key=key;
 
2584
    sort_param[i].keyinfo=share->keyinfo+key;
 
2585
    sort_param[i].seg=sort_param[i].keyinfo->seg;
 
2586
    /*
 
2587
      Skip this index if it is marked disabled in the copied
 
2588
      (and possibly inverted) key_map.
 
2589
    */
 
2590
    if (! mi_is_key_active(key_map, key))
 
2591
    {
 
2592
      /* Remember old statistics for key */
 
2593
      assert(rec_per_key_part >= param->rec_per_key_part);
 
2594
      memcpy(rec_per_key_part,
 
2595
             (share->state.rec_per_key_part +
 
2596
              (rec_per_key_part - param->rec_per_key_part)),
 
2597
             sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
 
2598
      istep=0;
 
2599
      continue;
 
2600
    }
 
2601
    istep=1;
 
2602
    if ((!(param->testflag & T_SILENT)))
 
2603
      printf ("- Fixing index %d\n",key+1);
 
2604
    {
 
2605
      sort_param[i].key_read=sort_key_read;
 
2606
      sort_param[i].key_write=sort_key_write;
 
2607
    }
 
2608
    sort_param[i].key_cmp=sort_key_cmp;
 
2609
    sort_param[i].lock_in_memory=lock_memory;
 
2610
    sort_param[i].tmpdir=param->tmpdir;
 
2611
    sort_param[i].sort_info=&sort_info;
 
2612
    sort_param[i].master=0;
 
2613
    sort_param[i].fix_datafile=0;
 
2614
    sort_param[i].calc_checksum= 0;
 
2615
 
 
2616
    sort_param[i].filepos=new_header_length;
 
2617
    sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
 
2618
 
 
2619
    sort_param[i].record= (((uchar *)(sort_param+share->base.keys))+
 
2620
                           (max_pack_reclength * i));
 
2621
    if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff))
 
2622
    {
 
2623
      mi_check_print_error(param,"Not enough memory!");
 
2624
      goto err;
 
2625
    }
 
2626
 
 
2627
    sort_param[i].key_length=share->rec_reflength;
 
2628
    for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END;
 
2629
         keyseg++)
 
2630
    {
 
2631
      sort_param[i].key_length+=keyseg->length;
 
2632
      if (keyseg->flag & HA_SPACE_PACK)
 
2633
        sort_param[i].key_length+=get_pack_length(keyseg->length);
 
2634
      if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
 
2635
        sort_param[i].key_length+=2 + test(keyseg->length >= 127);
 
2636
      if (keyseg->flag & HA_NULL_PART)
 
2637
        sort_param[i].key_length++;
 
2638
    }
 
2639
    total_key_length+=sort_param[i].key_length;
 
2640
  }
 
2641
  sort_info.total_keys=i;
 
2642
  sort_param[0].master= 1;
 
2643
  sort_param[0].fix_datafile= (bool)(! rep_quick);
 
2644
  sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
 
2645
 
 
2646
  sort_info.got_error=0;
 
2647
  pthread_mutex_lock(&sort_info.mutex);
 
2648
 
 
2649
  /*
 
2650
    Initialize the I/O cache share for use with the read caches and, in
 
2651
    case of non-quick repair, the write cache. When all threads join on
 
2652
    the cache lock, the writer copies the write cache contents to the
 
2653
    read caches.
 
2654
  */
 
2655
  if (i > 1)
 
2656
  {
 
2657
    if (rep_quick)
 
2658
      init_io_cache_share(&param->read_cache, &io_share, NULL, i);
 
2659
    else
 
2660
      init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i);
 
2661
  }
 
2662
  else
 
2663
    io_share.total_threads= 0; /* share not used */
 
2664
 
 
2665
  (void) pthread_attr_init(&thr_attr);
 
2666
  (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
 
2667
 
 
2668
  for (i=0 ; i < sort_info.total_keys ; i++)
 
2669
  {
 
2670
    /*
 
2671
      Copy the properly initialized IO_CACHE structure so that every
 
2672
      thread has its own copy. In quick mode param->read_cache is shared
 
2673
      for use by all threads. In non-quick mode all threads but the
 
2674
      first copy the shared new_data_cache, which is synchronized to the
 
2675
      write cache of the first thread. The first thread copies
 
2676
      param->read_cache, which is not shared.
 
2677
    */
 
2678
    sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache :
 
2679
                               new_data_cache);
 
2680
 
 
2681
    /*
 
2682
      two approaches: the same amount of memory for each thread
 
2683
      or the memory for the same number of keys for each thread...
 
2684
      In the second one all the threads will fill their sort_buffers
 
2685
      (and call write_keys) at the same time, putting more stress on i/o.
 
2686
    */
 
2687
    sort_param[i].sortbuff_size=
 
2688
#ifndef USING_SECOND_APPROACH
 
2689
      param->sort_buffer_length/sort_info.total_keys;
 
2690
#else
 
2691
      param->sort_buffer_length*sort_param[i].key_length/total_key_length;
 
2692
#endif
 
2693
    if (pthread_create(&sort_param[i].thr, &thr_attr,
 
2694
                       thr_find_all_keys,
 
2695
                       (void *) (sort_param+i)))
 
2696
    {
 
2697
      mi_check_print_error(param,"Cannot start a repair thread");
 
2698
      /* Cleanup: Detach from the share. Avoid others to be blocked. */
 
2699
      if (io_share.total_threads)
 
2700
        remove_io_thread(&sort_param[i].read_cache);
 
2701
      sort_info.got_error=1;
 
2702
    }
 
2703
    else
 
2704
      sort_info.threads_running++;
 
2705
  }
 
2706
  (void) pthread_attr_destroy(&thr_attr);
 
2707
 
 
2708
  /* waiting for all threads to finish */
 
2709
  while (sort_info.threads_running)
 
2710
    pthread_cond_wait(&sort_info.cond, &sort_info.mutex);
 
2711
  pthread_mutex_unlock(&sort_info.mutex);
 
2712
 
 
2713
  if ((got_error= thr_write_keys(sort_param)))
 
2714
  {
 
2715
    param->retry_repair=1;
 
2716
    goto err;
 
2717
  }
 
2718
  got_error=1;                          /* Assume the following may go wrong */
 
2719
 
 
2720
  if (sort_param[0].fix_datafile)
 
2721
  {
 
2722
    /*
 
2723
      Append some nuls to the end of a memory mapped file. Destroy the
 
2724
      write cache. The master thread did already detach from the share
 
2725
      by remove_io_thread() in sort.c:thr_find_all_keys().
 
2726
    */
 
2727
    if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
 
2728
      goto err;
 
2729
    if (param->testflag & T_SAFE_REPAIR)
 
2730
    {
 
2731
      /* Don't repair if we loosed more than one row */
 
2732
      if (info->state->records+1 < start_records)
 
2733
      {
 
2734
        info->state->records=start_records;
 
2735
        goto err;
 
2736
      }
 
2737
    }
 
2738
    share->state.state.data_file_length= info->state->data_file_length=
 
2739
      sort_param->filepos;
 
2740
    /* Only whole records */
 
2741
    share->state.version=(ulong) time((time_t*) 0);
 
2742
 
 
2743
    /*
 
2744
      Exchange the data file descriptor of the table, so that we use the
 
2745
      new file from now on.
 
2746
     */
 
2747
    my_close(info->dfile,MYF(0));
 
2748
    info->dfile=new_file;
 
2749
 
 
2750
    share->data_file_type=sort_info.new_data_file_type;
 
2751
    share->pack.header_length=(ulong) new_header_length;
 
2752
  }
 
2753
  else
 
2754
    info->state->data_file_length=sort_param->max_pos;
 
2755
 
 
2756
  if (rep_quick && del+sort_info.dupp != info->state->del)
 
2757
  {
 
2758
    mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
 
2759
    mi_check_print_error(param,"Run recovery again without -q");
 
2760
    param->retry_repair=1;
 
2761
    param->testflag|=T_RETRY_WITHOUT_QUICK;
 
2762
    goto err;
 
2763
  }
 
2764
 
 
2765
  if (rep_quick & T_FORCE_UNIQUENESS)
 
2766
  {
 
2767
    my_off_t skr=info->state->data_file_length+
 
2768
      (share->options & HA_OPTION_COMPRESS_RECORD ?
 
2769
       MEMMAP_EXTRA_MARGIN : 0);
 
2770
#ifdef USE_RELOC
 
2771
    if (share->data_file_type == STATIC_RECORD &&
 
2772
        skr < share->base.reloc*share->base.min_pack_length)
 
2773
      skr=share->base.reloc*share->base.min_pack_length;
 
2774
#endif
 
2775
    if (skr != sort_info.filelength && !info->s->base.raid_type)
 
2776
      if (ftruncate(info->dfile, skr))
 
2777
        mi_check_print_warning(param,
 
2778
                               "Can't change size of datafile,  error: %d",
 
2779
                               my_errno);
 
2780
  }
 
2781
  if (param->testflag & T_CALC_CHECKSUM)
 
2782
    info->state->checksum=param->glob_crc;
 
2783
 
 
2784
  if (ftruncate(share->kfile, info->state->key_file_length))
 
2785
    mi_check_print_warning(param,
 
2786
                           "Can't change size of indexfile, error: %d", my_errno);
 
2787
 
 
2788
  if (!(param->testflag & T_SILENT))
 
2789
  {
 
2790
    if (start_records != info->state->records)
 
2791
      printf("Data records: %s\n", llstr(info->state->records,llbuff));
 
2792
    if (sort_info.dupp)
 
2793
      mi_check_print_warning(param,
 
2794
                             "%s records have been removed",
 
2795
                             llstr(sort_info.dupp,llbuff));
 
2796
  }
 
2797
  got_error=0;
 
2798
 
 
2799
  if (&share->state.state != info->state)
 
2800
    memcpy(&share->state.state, info->state, sizeof(*info->state));
 
2801
 
 
2802
err:
 
2803
  got_error|= flush_blocks(param, share->key_cache, share->kfile);
 
2804
  /*
 
2805
    Destroy the write cache. The master thread did already detach from
 
2806
    the share by remove_io_thread() or it was not yet started (if the
 
2807
    error happend before creating the thread).
 
2808
  */
 
2809
  VOID(end_io_cache(&info->rec_cache));
 
2810
  /*
 
2811
    Destroy the new data cache in case of non-quick repair. All slave
 
2812
    threads did either detach from the share by remove_io_thread()
 
2813
    already or they were not yet started (if the error happend before
 
2814
    creating the threads).
 
2815
  */
 
2816
  if (!rep_quick)
 
2817
    VOID(end_io_cache(&new_data_cache));
 
2818
  if (!got_error)
 
2819
  {
 
2820
    /* Replace the actual file with the temporary file */
 
2821
    if (new_file >= 0)
 
2822
    {
 
2823
      my_close(new_file,MYF(0));
 
2824
      info->dfile=new_file= -1;
 
2825
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
 
2826
                            DATA_TMP_EXT, share->base.raid_chunks,
 
2827
                            (param->testflag & T_BACKUP_DATA ?
 
2828
                             MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
 
2829
          mi_open_datafile(info,share,-1))
 
2830
        got_error=1;
 
2831
    }
 
2832
  }
 
2833
  if (got_error)
 
2834
  {
 
2835
    if (! param->error_printed)
 
2836
      mi_check_print_error(param,"%d when fixing table",my_errno);
 
2837
    if (new_file >= 0)
 
2838
    {
 
2839
      VOID(my_close(new_file,MYF(0)));
 
2840
      VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks,
 
2841
                          MYF(MY_WME)));
 
2842
      if (info->dfile == new_file)
 
2843
        info->dfile= -1;
 
2844
    }
 
2845
    mi_mark_crashed_on_repair(info);
 
2846
  }
 
2847
  else if (key_map == share->state.key_map)
 
2848
    share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
 
2849
  share->state.changed|=STATE_NOT_SORTED_PAGES;
 
2850
 
 
2851
  pthread_cond_destroy (&sort_info.cond);
 
2852
  pthread_mutex_destroy(&sort_info.mutex);
 
2853
 
 
2854
  my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
 
2855
  my_free((uchar*) sort_param,MYF(MY_ALLOW_ZERO_PTR));
 
2856
  my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
 
2857
  VOID(end_io_cache(&param->read_cache));
 
2858
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
 
2859
  if (!got_error && (param->testflag & T_UNPACK))
 
2860
  {
 
2861
    share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
2338
2862
    share->pack.header_length=0;
2339
2863
  }
2340
2864
  return(got_error);
2342
2866
 
2343
2867
        /* Read next record and return next key */
2344
2868
 
2345
 
int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
 
2869
static int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
2346
2870
{
2347
2871
  int error;
2348
2872
  SORT_INFO *sort_info=sort_param->sort_info;
2359
2883
  }
2360
2884
  sort_param->real_key_length=
2361
2885
    (info->s->rec_reflength+
2362
 
     _mi_make_key(info, sort_param->key, (unsigned char*) key,
 
2886
     _mi_make_key(info, sort_param->key, (uchar*) key,
2363
2887
                  sort_param->record, sort_param->filepos));
2364
 
#ifdef HAVE_VALGRIND
2365
 
  memset((unsigned char *)key+sort_param->real_key_length, 0,
 
2888
#ifdef HAVE_purify
 
2889
  memset(key+sort_param->real_key_length, 0,
2366
2890
         (sort_param->key_length-sort_param->real_key_length));
2367
2891
#endif
2368
2892
  return(sort_write_record(sort_param));
2400
2924
    > 0         error
2401
2925
*/
2402
2926
 
2403
 
int sort_get_next_record(MI_SORT_PARAM *sort_param)
 
2927
static int sort_get_next_record(MI_SORT_PARAM *sort_param)
2404
2928
{
2405
2929
  int searching;
2406
2930
  int parallel_flag;
2407
 
  uint32_t found_record,b_type,left_length;
 
2931
  uint found_record,b_type,left_length;
2408
2932
  my_off_t pos;
2409
 
  unsigned char *to= NULL;
 
2933
  uchar *to= NULL;
2410
2934
  MI_BLOCK_INFO block_info;
2411
2935
  SORT_INFO *sort_info=sort_param->sort_info;
2412
2936
  MI_CHECK *param=sort_info->param;
2482
3006
                     llstr(param->search_after_block,llbuff),
2483
3007
                     llstr(sort_param->start_recpos,llbuff2));
2484
3008
        if (_mi_read_cache(&sort_param->read_cache,
2485
 
                           (unsigned char*) block_info.header,pos,
 
3009
                           (uchar*) block_info.header,pos,
2486
3010
                           MI_BLOCK_INFO_HEADER_LENGTH,
2487
3011
                           (! found_record ? READING_NEXT : 0) |
2488
3012
                           parallel_flag | READING_HEADER))
2509
3033
             (block_info.rec_len < (uint) share->base.min_pack_length ||
2510
3034
              block_info.rec_len > (uint) share->base.max_pack_length)))
2511
3035
        {
2512
 
          uint32_t i;
 
3036
          uint i;
2513
3037
          if (param->testflag & T_VERBOSE || searching == 0)
2514
3038
            mi_check_print_info(param,
2515
3039
                                "Wrong bytesec: %3d-%3d-%3d at %10s; Skipped",
2668
3192
          streched over the end of the previous buffer contents.
2669
3193
        */
2670
3194
        {
2671
 
          uint32_t header_len= (uint) (block_info.filepos - pos);
2672
 
          uint32_t prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len);
 
3195
          uint header_len= (uint) (block_info.filepos - pos);
 
3196
          uint prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len);
2673
3197
 
2674
3198
          if (prefetch_len > block_info.data_len)
2675
3199
            prefetch_len= block_info.data_len;
2690
3214
        {
2691
3215
          mi_check_print_info(param,
2692
3216
                              "Read error for block at: %s (error: %d); Skipped",
2693
 
                              llstr(block_info.filepos,llbuff),errno);
 
3217
                              llstr(block_info.filepos,llbuff),my_errno);
2694
3218
          goto try_next;
2695
3219
        }
2696
3220
        left_length-=block_info.data_len;
2770
3294
{
2771
3295
  int flag;
2772
3296
  ulong block_length,reclength;
2773
 
  unsigned char *from;
 
3297
  uchar *from;
2774
3298
  SORT_INFO *sort_info=sort_param->sort_info;
2775
3299
  MI_CHECK *param=sort_info->param;
2776
3300
  MI_INFO *info=sort_info->info;
2783
3307
      if (my_b_write(&info->rec_cache,sort_param->record,
2784
3308
                     share->base.pack_reclength))
2785
3309
      {
2786
 
        mi_check_print_error(param,"%d when writing to datafile",errno);
 
3310
        mi_check_print_error(param,"%d when writing to datafile",my_errno);
2787
3311
        return(1);
2788
3312
      }
2789
3313
      sort_param->filepos+=share->base.pack_reclength;
2802
3326
          MI_DYN_DELETE_BLOCK_HEADER;
2803
3327
        if (sort_info->buff_length < reclength)
2804
3328
        {
2805
 
          void *tmpptr= NULL;
2806
 
          tmpptr= realloc(sort_info->buff, reclength);
2807
 
          if(tmpptr)
2808
 
          {
2809
 
            sort_info->buff_length=reclength;
2810
 
            sort_info->buff= (unsigned char *)tmpptr;
2811
 
          }
2812
 
          else
2813
 
          {
2814
 
            mi_check_print_error(param,"Could not realloc() sort_info->buff "
2815
 
                                 " to %ul bytes", reclength);
2816
 
            return(1);
2817
 
          }
 
3329
          if (!(sort_info->buff=my_realloc(sort_info->buff, (uint) reclength,
 
3330
                                           MYF(MY_FREE_ON_ERROR |
 
3331
                                               MY_ALLOW_ZERO_PTR))))
 
3332
            return(1);
 
3333
          sort_info->buff_length=reclength;
2818
3334
        }
2819
3335
        from= sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
2820
3336
      }
2837
3353
                                  sort_param->filepos+block_length,
2838
3354
                                  &from,&reclength,&flag))
2839
3355
        {
2840
 
          mi_check_print_error(param,"%d when writing to datafile",errno);
 
3356
          mi_check_print_error(param,"%d when writing to datafile",my_errno);
2841
3357
          return(1);
2842
3358
        }
2843
3359
        sort_param->filepos+=block_length;
2858
3374
    {
2859
3375
      char llbuff[22];
2860
3376
      printf("%s\r", llstr(info->state->records,llbuff));
2861
 
      fflush(stdout);
 
3377
      VOID(fflush(stdout));
2862
3378
    }
2863
3379
  }
2864
3380
  return(0);
2867
3383
 
2868
3384
        /* Compare two keys from _create_index_by_sort */
2869
3385
 
2870
 
int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a, const void *b)
 
3386
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,
 
3387
                        const void *b)
2871
3388
{
2872
 
  uint32_t not_used[2];
2873
 
  return (ha_key_cmp(sort_param->seg, *((unsigned char* const *) a), *((unsigned char* const *) b),
 
3389
  uint not_used[2];
 
3390
  return (ha_key_cmp(sort_param->seg, *((uchar* const *) a), *((uchar* const *) b),
2874
3391
                     USE_WHOLE_KEY, SEARCH_SAME, not_used));
2875
3392
} /* sort_key_cmp */
2876
3393
 
2877
3394
 
2878
 
int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
 
3395
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
2879
3396
{
2880
 
  uint32_t diff_pos[2];
 
3397
  uint diff_pos[2];
2881
3398
  char llbuff[22],llbuff2[22];
2882
3399
  SORT_INFO *sort_info=sort_param->sort_info;
2883
3400
  MI_CHECK *param= sort_info->param;
2886
3403
  if (sort_info->key_block->inited)
2887
3404
  {
2888
3405
    cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
2889
 
                   (unsigned char*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
 
3406
                   (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
2890
3407
                   diff_pos);
2891
3408
    if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
2892
3409
      ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
2893
 
                 (unsigned char*) a, USE_WHOLE_KEY,
 
3410
                 (uchar*) a, USE_WHOLE_KEY, 
2894
3411
                 SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
2895
3412
    else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
2896
3413
    {
2897
3414
      diff_pos[0]= mi_collect_stats_nonulls_next(sort_param->seg,
2898
3415
                                                 sort_param->notnull,
2899
3416
                                                 sort_info->key_block->lastkey,
2900
 
                                                 (unsigned char*)a);
 
3417
                                                 (uchar*)a);
2901
3418
    }
2902
3419
    sort_param->unique[diff_pos[0]-1]++;
2903
3420
  }
2906
3423
    cmp= -1;
2907
3424
    if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
2908
3425
      mi_collect_stats_nonulls_first(sort_param->seg, sort_param->notnull,
2909
 
                                     (unsigned char*)a);
 
3426
                                     (uchar*)a);
2910
3427
  }
2911
3428
  if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0)
2912
3429
  {
2913
3430
    sort_info->dupp++;
2914
3431
    sort_info->info->lastpos=get_record_for_key(sort_info->info,
2915
3432
                                                sort_param->keyinfo,
2916
 
                                                (unsigned char*) a);
 
3433
                                                (uchar*) a);
2917
3434
    mi_check_print_warning(param,
2918
3435
                           "Duplicate key for record at %10s against record at %10s",
2919
3436
                           llstr(sort_info->info->lastpos,llbuff),
2926
3443
    return (sort_delete_record(sort_param));
2927
3444
  }
2928
3445
  return (sort_insert_key(sort_param,sort_info->key_block,
2929
 
                          (unsigned char*) a, HA_OFFSET_ERROR));
 
3446
                          (uchar*) a, HA_OFFSET_ERROR));
2930
3447
} /* sort_key_write */
2931
3448
 
2932
3449
 
2933
3450
        /* get pointer to record from a key */
2934
3451
 
2935
 
my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo,
2936
 
                            unsigned char *key) {
 
3452
static my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo,
 
3453
                                   uchar *key)
 
3454
{
2937
3455
  return _mi_dpos(info,0,key+_mi_keylength(keyinfo,key));
2938
3456
} /* get_record_for_key */
2939
3457
 
2940
3458
 
2941
3459
        /* Insert a key in sort-key-blocks */
2942
3460
 
2943
 
int sort_insert_key(MI_SORT_PARAM *sort_param,
2944
 
                    register SORT_KEY_BLOCKS *key_block, unsigned char *key,
2945
 
                    my_off_t prev_block)
 
3461
static int sort_insert_key(MI_SORT_PARAM *sort_param,
 
3462
                           register SORT_KEY_BLOCKS *key_block, uchar *key,
 
3463
                           my_off_t prev_block)
2946
3464
{
2947
 
  uint32_t a_length,t_length,nod_flag;
 
3465
  uint a_length,t_length,nod_flag;
2948
3466
  my_off_t filepos,key_file_length;
2949
 
  unsigned char *anc_buff,*lastkey;
 
3467
  uchar *anc_buff,*lastkey;
2950
3468
  MI_KEY_PARAM s_temp;
2951
3469
  MI_INFO *info;
2952
3470
  MI_KEYDEF *keyinfo=sort_param->keyinfo;
2979
3497
    _mi_kpointer(info,key_block->end_pos,prev_block);
2980
3498
 
2981
3499
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
2982
 
                                (unsigned char*) 0,lastkey,lastkey,key,
 
3500
                                (uchar*) 0,lastkey,lastkey,key,
2983
3501
                                 &s_temp);
2984
3502
  (*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp);
2985
3503
  a_length+=t_length;
2987
3505
  key_block->end_pos+=t_length;
2988
3506
  if (a_length <= keyinfo->block_length)
2989
3507
  {
2990
 
    _mi_move_key(keyinfo,key_block->lastkey,key);
 
3508
    VOID(_mi_move_key(keyinfo,key_block->lastkey,key));
2991
3509
    key_block->last_length=a_length-t_length;
2992
3510
    return(0);
2993
3511
  }
3006
3524
    if (_mi_write_keypage(info, keyinfo, filepos, DFLT_INIT_HITS, anc_buff))
3007
3525
      return(1);
3008
3526
  }
3009
 
  else if (my_pwrite(info->s->kfile,(unsigned char*) anc_buff,
 
3527
  else if (my_pwrite(info->s->kfile,(uchar*) anc_buff,
3010
3528
                     (uint) keyinfo->block_length,filepos, param->myf_rw))
3011
3529
    return(1);
3012
3530
 
3022
3540
 
3023
3541
        /* Delete record when we found a duplicated key */
3024
3542
 
3025
 
int sort_delete_record(MI_SORT_PARAM *sort_param)
 
3543
static int sort_delete_record(MI_SORT_PARAM *sort_param)
3026
3544
{
3027
 
  uint32_t i;
 
3545
  uint i;
3028
3546
  int old_file,error;
3029
 
  unsigned char *key;
 
3547
  uchar *key;
3030
3548
  SORT_INFO *sort_info=sort_param->sort_info;
3031
3549
  MI_CHECK *param=sort_info->param;
3032
3550
  MI_INFO *info=sort_info->info;
3059
3577
 
3060
3578
    for (i=0 ; i < sort_info->current_key ; i++)
3061
3579
    {
3062
 
      uint32_t key_length=_mi_make_key(info,i,key,sort_param->record,info->lastpos);
 
3580
      uint key_length=_mi_make_key(info,i,key,sort_param->record,info->lastpos);
3063
3581
      if (_mi_ck_delete(info,i,key,key_length))
3064
3582
      {
3065
3583
        mi_check_print_error(param,"Can't delete key %d from record to be removed",i+1);
3080
3598
 
3081
3599
int flush_pending_blocks(MI_SORT_PARAM *sort_param)
3082
3600
{
3083
 
  uint32_t nod_flag,length;
 
3601
  uint nod_flag,length;
3084
3602
  my_off_t filepos,key_file_length;
3085
3603
  SORT_KEY_BLOCKS *key_block;
3086
3604
  SORT_INFO *sort_info= sort_param->sort_info;
3108
3626
                            DFLT_INIT_HITS, key_block->buff))
3109
3627
        return(1);
3110
3628
    }
3111
 
    else if (my_pwrite(info->s->kfile,(unsigned char*) key_block->buff,
 
3629
    else if (my_pwrite(info->s->kfile,(uchar*) key_block->buff,
3112
3630
                       (uint) keyinfo->block_length,filepos, myf_rw))
3113
3631
      return(1);
3114
3632
    nod_flag=1;
3119
3637
 
3120
3638
        /* alloc space and pointers for key_blocks */
3121
3639
 
3122
 
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint32_t blocks,
3123
 
                                         uint32_t buffer_length)
 
3640
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
 
3641
                                         uint buffer_length)
3124
3642
{
3125
 
  register uint32_t i;
 
3643
  register uint i;
3126
3644
  SORT_KEY_BLOCKS *block;
3127
3645
 
3128
 
  if (!(block=(SORT_KEY_BLOCKS*) malloc((sizeof(SORT_KEY_BLOCKS)+
3129
 
                                        buffer_length+IO_SIZE)*blocks)))
 
3646
  if (!(block=(SORT_KEY_BLOCKS*) my_malloc((sizeof(SORT_KEY_BLOCKS)+
 
3647
                                            buffer_length+IO_SIZE)*blocks,
 
3648
                                           MYF(0))))
3130
3649
  {
3131
3650
    mi_check_print_error(param,"Not enough memory for sort-key-blocks");
3132
3651
    return(0);
3134
3653
  for (i=0 ; i < blocks ; i++)
3135
3654
  {
3136
3655
    block[i].inited=0;
3137
 
    block[i].buff=(unsigned char*) (block+blocks)+(buffer_length+IO_SIZE)*i;
 
3656
    block[i].buff=(uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
3138
3657
  }
3139
3658
  return(block);
3140
3659
} /* alloc_key_blocks */
3146
3665
{
3147
3666
  if (info->s->options & HA_OPTION_COMPRESS_RECORD)
3148
3667
    return 0;
3149
 
  return (my_off_t)(lseek(info->s->kfile, 0L, SEEK_END) / 10 * 9) >
 
3668
  return my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(MY_THREADSAFE)) / 10 * 9 >
3150
3669
         (my_off_t) info->s->base.max_key_file_length ||
3151
 
         (my_off_t)(lseek(info->dfile, 0L, SEEK_END) / 10 * 9) >
 
3670
         my_seek(info->dfile, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 >
3152
3671
         (my_off_t) info->s->base.max_data_file_length;
3153
3672
}
3154
3673
 
 
3674
        /* Recreate table with bigger more alloced record-data */
 
3675
 
 
3676
int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
 
3677
{
 
3678
  int error;
 
3679
  MI_INFO info;
 
3680
  MYISAM_SHARE share;
 
3681
  MI_KEYDEF *keyinfo,*key,*key_end;
 
3682
  HA_KEYSEG *keysegs,*keyseg;
 
3683
  MI_COLUMNDEF *recdef,*rec,*end;
 
3684
  MI_UNIQUEDEF *uniquedef,*u_ptr,*u_end;
 
3685
  MI_STATUS_INFO status_info;
 
3686
  uint unpack,key_parts;
 
3687
  ha_rows max_records;
 
3688
  uint64_t file_length,tmp_length;
 
3689
  MI_CREATE_INFO create_info;
 
3690
 
 
3691
  error=1;                                      /* Default error */
 
3692
  info= **org_info;
 
3693
  status_info= (*org_info)->state[0];
 
3694
  info.state= &status_info;
 
3695
  share= *(*org_info)->s;
 
3696
  unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
 
3697
    (param->testflag & T_UNPACK);
 
3698
  if (!(keyinfo=(MI_KEYDEF*) my_alloca(sizeof(MI_KEYDEF)*share.base.keys)))
 
3699
    return(0);
 
3700
  memcpy(keyinfo,share.keyinfo,sizeof(MI_KEYDEF)*share.base.keys);
 
3701
 
 
3702
  key_parts= share.base.all_key_parts;
 
3703
  if (!(keysegs=(HA_KEYSEG*) my_alloca(sizeof(HA_KEYSEG)*
 
3704
                                       (key_parts+share.base.keys))))
 
3705
  {
 
3706
    my_afree((uchar*) keyinfo);
 
3707
    return(1);
 
3708
  }
 
3709
  if (!(recdef=(MI_COLUMNDEF*)
 
3710
        my_alloca(sizeof(MI_COLUMNDEF)*(share.base.fields+1))))
 
3711
  {
 
3712
    my_afree((uchar*) keyinfo);
 
3713
    my_afree((uchar*) keysegs);
 
3714
    return(1);
 
3715
  }
 
3716
  if (!(uniquedef=(MI_UNIQUEDEF*)
 
3717
        my_alloca(sizeof(MI_UNIQUEDEF)*(share.state.header.uniques+1))))
 
3718
  {
 
3719
    my_afree((uchar*) recdef);
 
3720
    my_afree((uchar*) keyinfo);
 
3721
    my_afree((uchar*) keysegs);
 
3722
    return(1);
 
3723
  }
 
3724
 
 
3725
  /* Copy the column definitions */
 
3726
  memcpy(recdef, share.rec, sizeof(MI_COLUMNDEF)*(share.base.fields+1));
 
3727
  for (rec=recdef,end=recdef+share.base.fields; rec != end ; rec++)
 
3728
  {
 
3729
    if (unpack && !(share.options & HA_OPTION_PACK_RECORD) &&
 
3730
        rec->type != FIELD_BLOB &&
 
3731
        rec->type != FIELD_VARCHAR &&
 
3732
        rec->type != FIELD_CHECK)
 
3733
      rec->type=(int) FIELD_NORMAL;
 
3734
  }
 
3735
 
 
3736
  /* Change the new key to point at the saved key segments */
 
3737
  memcpy(keysegs,share.keyparts,
 
3738
         sizeof(HA_KEYSEG)*(key_parts+share.base.keys+
 
3739
                            share.state.header.uniques));
 
3740
  keyseg=keysegs;
 
3741
  for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
 
3742
  {
 
3743
    key->seg=keyseg;
 
3744
    for (; keyseg->type ; keyseg++)
 
3745
    {
 
3746
      if (param->language)
 
3747
        keyseg->language=param->language;       /* change language */
 
3748
    }
 
3749
    keyseg++;                                   /* Skip end pointer */
 
3750
  }
 
3751
 
 
3752
  /* Copy the unique definitions and change them to point at the new key
 
3753
     segments*/
 
3754
  memcpy(uniquedef,share.uniqueinfo,
 
3755
         sizeof(MI_UNIQUEDEF)*(share.state.header.uniques));
 
3756
  for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques;
 
3757
       u_ptr != u_end ; u_ptr++)
 
3758
  {
 
3759
    u_ptr->seg=keyseg;
 
3760
    keyseg+=u_ptr->keysegs+1;
 
3761
  }
 
3762
  if (share.options & HA_OPTION_COMPRESS_RECORD)
 
3763
    share.base.records=max_records=info.state->records;
 
3764
  else if (share.base.min_pack_length)
 
3765
    max_records=(ha_rows) (my_seek(info.dfile,0L,MY_SEEK_END,MYF(0)) /
 
3766
                           (ulong) share.base.min_pack_length);
 
3767
  else
 
3768
    max_records=0;
 
3769
  unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
 
3770
    (param->testflag & T_UNPACK);
 
3771
  share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
 
3772
 
 
3773
  file_length=(uint64_t) my_seek(info.dfile,0L,MY_SEEK_END,MYF(0));
 
3774
  tmp_length= file_length+file_length/10;
 
3775
  set_if_bigger(file_length,param->max_data_file_length);
 
3776
  set_if_bigger(file_length,tmp_length);
 
3777
  set_if_bigger(file_length,(uint64_t) share.base.max_data_file_length);
 
3778
 
 
3779
  VOID(mi_close(*org_info));
 
3780
  memset(&create_info, 0, sizeof(create_info));
 
3781
  create_info.max_rows=max(max_records,share.base.records);
 
3782
  create_info.reloc_rows=share.base.reloc;
 
3783
  create_info.old_options=(share.options |
 
3784
                           (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));
 
3785
 
 
3786
  create_info.data_file_length=file_length;
 
3787
  create_info.auto_increment=share.state.auto_increment;
 
3788
  create_info.language = (param->language ? param->language :
 
3789
                          share.state.header.language);
 
3790
  create_info.key_file_length=  status_info.key_file_length;
 
3791
  /*
 
3792
    Allow for creating an auto_increment key. This has an effect only if
 
3793
    an auto_increment key exists in the original table.
 
3794
  */
 
3795
  create_info.with_auto_increment= true;
 
3796
  /* We don't have to handle symlinks here because we are using
 
3797
     HA_DONT_TOUCH_DATA */
 
3798
  if (mi_create(filename,
 
3799
                share.base.keys - share.state.header.uniques,
 
3800
                keyinfo, share.base.fields, recdef,
 
3801
                share.state.header.uniques, uniquedef,
 
3802
                &create_info,
 
3803
                HA_DONT_TOUCH_DATA))
 
3804
  {
 
3805
    mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno);
 
3806
    goto end;
 
3807
  }
 
3808
  *org_info=mi_open(filename,O_RDWR,
 
3809
                    (param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
 
3810
                    (param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
 
3811
                    HA_OPEN_ABORT_IF_LOCKED);
 
3812
  if (!*org_info)
 
3813
  {
 
3814
    mi_check_print_error(param,"Got error %d when trying to open re-created indexfile",
 
3815
                my_errno);
 
3816
    goto end;
 
3817
  }
 
3818
  /* We are modifing */
 
3819
  (*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
 
3820
  VOID(_mi_readinfo(*org_info,F_WRLCK,0));
 
3821
  (*org_info)->state->records=info.state->records;
 
3822
  if (share.state.create_time)
 
3823
    (*org_info)->s->state.create_time=share.state.create_time;
 
3824
  (*org_info)->s->state.unique=(*org_info)->this_unique=
 
3825
    share.state.unique;
 
3826
  (*org_info)->state->checksum=info.state->checksum;
 
3827
  (*org_info)->state->del=info.state->del;
 
3828
  (*org_info)->s->state.dellink=share.state.dellink;
 
3829
  (*org_info)->state->empty=info.state->empty;
 
3830
  (*org_info)->state->data_file_length=info.state->data_file_length;
 
3831
  if (update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
 
3832
                        UPDATE_OPEN_COUNT))
 
3833
    goto end;
 
3834
  error=0;
 
3835
end:
 
3836
  my_afree((uchar*) uniquedef);
 
3837
  my_afree((uchar*) keyinfo);
 
3838
  my_afree((uchar*) recdef);
 
3839
  my_afree((uchar*) keysegs);
 
3840
  return(error);
 
3841
}
 
3842
 
3155
3843
 
3156
3844
        /* write suffix to data file if neaded */
3157
3845
 
3161
3849
 
3162
3850
  if (info->s->options & HA_OPTION_COMPRESS_RECORD && fix_datafile)
3163
3851
  {
3164
 
    unsigned char buff[MEMMAP_EXTRA_MARGIN];
 
3852
    uchar buff[MEMMAP_EXTRA_MARGIN];
3165
3853
    memset(buff, 0, sizeof(buff));
3166
3854
    if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
3167
3855
    {
3168
3856
      mi_check_print_error(sort_info->param,
3169
 
                           "%d when writing to datafile",errno);
 
3857
                           "%d when writing to datafile",my_errno);
3170
3858
      return 1;
3171
3859
    }
3172
3860
    sort_info->param->read_cache.end_of_file+=sizeof(buff);
3176
3864
 
3177
3865
        /* Update state and myisamchk_time of indexfile */
3178
3866
 
3179
 
int update_state_info(MI_CHECK *param, MI_INFO *info,uint32_t update)
 
3867
int update_state_info(MI_CHECK *param, MI_INFO *info,uint update)
3180
3868
{
3181
3869
  MYISAM_SHARE *share=info->s;
3182
3870
 
3187
3875
  }
3188
3876
  if (update & UPDATE_STAT)
3189
3877
  {
3190
 
    uint32_t i, key_parts= mi_uint2korr(share->state.header.key_parts);
 
3878
    uint i, key_parts= mi_uint2korr(share->state.header.key_parts);
3191
3879
    share->state.rec_per_key_rows=info->state->records;
3192
3880
    share->state.changed&= ~STATE_NOT_ANALYZED;
3193
3881
    if (info->state->records)
3221
3909
  }
3222
3910
  {                                             /* Force update of status */
3223
3911
    int error;
3224
 
    uint32_t r_locks=share->r_locks,w_locks=share->w_locks;
 
3912
    uint r_locks=share->r_locks,w_locks=share->w_locks;
3225
3913
    share->r_locks= share->w_locks= share->tot_locks= 0;
3226
3914
    error=_mi_writeinfo(info,WRITEINFO_NO_UNLOCK);
3227
3915
    share->r_locks=r_locks;
3231
3919
      return 0;
3232
3920
  }
3233
3921
err:
3234
 
  mi_check_print_error(param,"%d when updating keyfile",errno);
 
3922
  mi_check_print_error(param,"%d when updating keyfile",my_errno);
3235
3923
  return 1;
3236
3924
}
3237
3925
 
3251
3939
void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
3252
3940
                               bool repair_only)
3253
3941
{
3254
 
  unsigned char *record= 0;
 
3942
  uchar *record= 0;
3255
3943
 
3256
3944
  if (!info->s->base.auto_key ||
3257
3945
      ! mi_is_key_active(info->s->state.key_map, info->s->base.auto_key - 1))
3266
3954
      !(param->testflag & T_REP))
3267
3955
    printf("Updating MyISAM file: %s\n", param->isam_file_name);
3268
3956
  /*
3269
 
    We have to use an allocated buffer instead of info->rec_buff as
 
3957
    We have to use an allocated buffer instead of info->rec_buff as 
3270
3958
    _mi_put_key_in_record() may use info->rec_buff
3271
3959
  */
3272
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
 
3960
  if (!mi_alloc_rec_buff(info, -1, &record))
3273
3961
  {
3274
3962
    mi_check_print_error(param,"Not enough memory for extra record");
3275
3963
    return;
3278
3966
  mi_extra(info,HA_EXTRA_KEYREAD,0);
3279
3967
  if (mi_rlast(info, record, info->s->base.auto_key-1))
3280
3968
  {
3281
 
    if (errno != HA_ERR_END_OF_FILE)
 
3969
    if (my_errno != HA_ERR_END_OF_FILE)
3282
3970
    {
3283
3971
      mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
3284
 
      free(mi_get_rec_buff_ptr(info, record));
3285
 
      mi_check_print_error(param,"%d when reading last record",errno);
 
3972
      my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
 
3973
      mi_check_print_error(param,"%d when reading last record",my_errno);
3286
3974
      return;
3287
3975
    }
3288
3976
    if (!repair_only)
3296
3984
      set_if_bigger(info->s->state.auto_increment, param->auto_increment_value);
3297
3985
  }
3298
3986
  mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
3299
 
  free(mi_get_rec_buff_ptr(info, record));
 
3987
  my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
3300
3988
  update_state_info(param, info, UPDATE_AUTO_INC);
3301
3989
  return;
3302
3990
}
3314
4002
      records               Number of records in the table
3315
4003
 
3316
4004
  DESCRIPTION
3317
 
    This function is called produce index statistics values from unique and
 
4005
    This function is called produce index statistics values from unique and 
3318
4006
    notnull_tuples arrays after these arrays were produced with sequential
3319
4007
    index scan (the scan is done in two places: chk_index() and
3320
4008
    sort_key_write()).
3328
4016
 
3329
4017
    For MI_STATS_METHOD_IGNORE_NULLS method, notnull_tuples is an array too:
3330
4018
      notnull_tuples[0]= (#of {keypart1} tuples such that keypart1 is not NULL)
3331
 
      notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all
 
4019
      notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all 
3332
4020
                          keypart{i} are not NULL)
3333
4021
      ...
3334
4022
    For all other statistics collection methods notnull_tuples==NULL.
3335
4023
 
3336
4024
    Output is an array:
3337
 
    rec_per_key_part[k] =
3338
 
     = E(#records in the table such that keypart_1=c_1 AND ... AND
3339
 
         keypart_k=c_k for arbitrary constants c_1 ... c_k)
3340
 
 
 
4025
    rec_per_key_part[k] = 
 
4026
     = E(#records in the table such that keypart_1=c_1 AND ... AND 
 
4027
         keypart_k=c_k for arbitrary constants c_1 ... c_k) 
 
4028
     
3341
4029
     = {assuming that values have uniform distribution and index contains all
3342
4030
        tuples from the domain (or that {c_1, ..., c_k} tuple is choosen from
3343
4031
        index tuples}
3344
 
 
 
4032
     
3345
4033
     = #tuples-in-the-index / #distinct-tuples-in-the-index.
3346
 
 
3347
 
    The #tuples-in-the-index and #distinct-tuples-in-the-index have different
 
4034
    
 
4035
    The #tuples-in-the-index and #distinct-tuples-in-the-index have different 
3348
4036
    meaning depending on which statistics collection method is used:
3349
 
 
 
4037
    
3350
4038
    MI_STATS_METHOD_*  how are nulls compared?  which tuples are counted?
3351
4039
     NULLS_EQUAL            NULL == NULL           all tuples in table
3352
4040
     NULLS_NOT_EQUAL        NULL != NULL           all tuples in table
3359
4047
{
3360
4048
  uint64_t count=0,tmp, unique_tuples;
3361
4049
  uint64_t tuples= records;
3362
 
  uint32_t parts;
 
4050
  uint parts;
3363
4051
  for (parts=0 ; parts < keyinfo->keysegs  ; parts++)
3364
4052
  {
3365
4053
    count+=unique[parts];
3366
 
    unique_tuples= count + 1;
 
4054
    unique_tuples= count + 1;    
3367
4055
    if (notnull)
3368
4056
    {
3369
4057
      tuples= notnull[parts];
3370
 
      /*
3371
 
        #(unique_tuples not counting tuples with NULLs) =
3372
 
          #(unique_tuples counting tuples with NULLs as different) -
 
4058
      /* 
 
4059
        #(unique_tuples not counting tuples with NULLs) = 
 
4060
          #(unique_tuples counting tuples with NULLs as different) - 
3373
4061
          #(tuples with NULLs)
3374
4062
      */
3375
4063
      unique_tuples -= (records - notnull[parts]);
3376
4064
    }
3377
 
 
 
4065
    
3378
4066
    if (unique_tuples == 0)
3379
4067
      tmp= 1;
3380
4068
    else if (count == 0)
3382
4070
    else
3383
4071
      tmp= (tuples + unique_tuples/2) / unique_tuples;
3384
4072
 
3385
 
    /*
3386
 
      for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
 
4073
    /* 
 
4074
      for some weird keys (e.g. FULLTEXT) tmp can be <1 here. 
3387
4075
      let's ensure it is not
3388
4076
    */
3389
 
    if (tmp < 1)
3390
 
      tmp= 1;
 
4077
    set_if_bigger(tmp,1);
3391
4078
    if (tmp >= (uint64_t) ~(ulong) 0)
3392
4079
      tmp=(uint64_t) ~(ulong) 0;
3393
4080
 
3397
4084
}
3398
4085
 
3399
4086
 
3400
 
static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length)
 
4087
static ha_checksum mi_byte_checksum(const uchar *buf, uint length)
3401
4088
{
3402
4089
  ha_checksum crc;
3403
 
  const unsigned char *end=buf+length;
 
4090
  const uchar *end=buf+length;
3404
4091
  for (crc=0; buf != end; buf++)
3405
 
    crc=((crc << 1) + *((unsigned char*) buf)) +
 
4092
    crc=((crc << 1) + *((uchar*) buf)) +
3406
4093
      test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1)));
3407
4094
  return crc;
3408
4095
}
3409
4096
 
3410
4097
static bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows)
3411
4098
{
3412
 
  uint32_t key_maxlength=key->maxlength;
 
4099
  uint key_maxlength=key->maxlength;
3413
4100
  return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY) &&
3414
4101
          ((uint64_t) rows * key_maxlength >
3415
 
           (uint64_t) MAX_FILE_SIZE));
 
4102
           (uint64_t) myisam_max_temp_length));
3416
4103
}
3417
4104
 
3418
4105
/*
3428
4115
{
3429
4116
  MYISAM_SHARE *share=info->s;
3430
4117
  MI_KEYDEF    *key=share->keyinfo;
3431
 
  uint32_t          i;
 
4118
  uint          i;
3432
4119
 
3433
4120
  assert(info->state->records == 0 &&
3434
4121
              (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES));
3455
4142
{
3456
4143
  MYISAM_SHARE *share=info->s;
3457
4144
  MI_KEYDEF *key=share->keyinfo;
3458
 
  uint32_t i;
 
4145
  uint i;
3459
4146
 
3460
4147
  /*
3461
4148
    mi_repair_by_sort only works if we have at least one key. If we don't