~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mi_check.c

  • Committer: Monty Taylor
  • Date: 2008-08-01 22:33:44 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801223344-vzhlflfmtijp1imv
First pass at gettexizing the error messages.

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)
96
86
{
97
 
  memset(param, 0, sizeof(*param));
 
87
  memset((uchar*) param, 0, sizeof(*param));
98
88
  param->opt_follow_links=1;
99
89
  param->keys_in_use= ~(uint64_t) 0;
100
90
  param->search_after_block=HA_OFFSET_ERROR;
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;
434
430
    if (! mi_is_key_active(share->state.key_map, key))
435
431
    {
436
432
      /* Remember old statistics for key */
437
 
      assert(rec_per_key_part >= param->rec_per_key_part);
438
 
      memcpy(rec_per_key_part,
439
 
             (share->state.rec_per_key_part +
440
 
              (rec_per_key_part - param->rec_per_key_part)),
 
433
      memcpy((char*) rec_per_key_part,
 
434
             (char*) (share->state.rec_per_key_part +
 
435
                      (uint) (rec_per_key_part - param->rec_per_key_part)),
441
436
             keyinfo->keysegs*sizeof(*rec_per_key_part));
442
437
      continue;
443
438
    }
444
439
    found_keys++;
445
440
 
446
441
    param->record_checksum=init_checksum;
447
 
 
448
 
    memset(&param->unique_count, 0, sizeof(param->unique_count));
449
 
    memset(&param->notnull_count, 0, sizeof(param->notnull_count));
 
442
    
 
443
    memset((char*) &param->unique_count, 0, sizeof(param->unique_count));
 
444
    memset((char*) &param->notnull_count, 0, sizeof(param->notnull_count));
450
445
 
451
446
    if ((!(param->testflag & T_SILENT)))
452
447
      printf ("- check data record references index: %d\n",key+1);
453
 
    if (share->state.key_root[key] == HA_OFFSET_ERROR && (info->state->records == 0))
 
448
    if (share->state.key_root[key] == HA_OFFSET_ERROR &&
 
449
        (info->state->records == 0 || keyinfo->flag & HA_FULLTEXT))
454
450
      goto do_stat;
455
451
    if (!_mi_fetch_keypage(info,keyinfo,share->state.key_root[key],
456
452
                           DFLT_INIT_HITS,info->buff,0))
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;
470
466
    if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff,
471
467
                  &keys, param->key_crc+key,1))
472
468
      return(-1);
473
 
    if(!(0))
 
469
    if(!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL)))
474
470
    {
475
471
      if (keys != info->state->records)
476
472
      {
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);
756
759
  {
757
760
    if (*killed_ptr(param))
758
761
      goto err;
759
 
    memcpy(info->lastkey,key,key_length);
 
762
    memcpy((char*) info->lastkey,(char*) key,key_length);
760
763
    info->lastkey_length=key_length;
761
764
    if (nod_flag)
762
765
    {
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];
885
 
  bool static_row_size;
 
888
  my_bool static_row_size;
886
889
  MI_KEYDEF *keyinfo;
887
890
  MI_BLOCK_INFO block_info;
888
891
 
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);
921
924
  }
922
925
 
923
926
  pos=my_b_tell(&param->read_cache);
924
 
  memset(key_checksum, 0, info->s->base.keys * sizeof(key_checksum[0]));
 
927
  memset((char*) key_checksum, 0, info->s->base.keys * sizeof(key_checksum[0]));
925
928
  while (pos < info->state->data_file_length)
926
929
  {
927
930
    if (*killed_ptr(param))
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;
1113
1116
        pos=block_info.filepos+block_info.block_len;
1114
1117
      break;
1115
1118
    case COMPRESSED_RECORD:
 
1119
      if (_mi_read_cache(&param->read_cache,(uchar*) block_info.header, pos,
 
1120
                         info->s->pack.ref_length, READING_NEXT))
 
1121
        goto err;
 
1122
      start_recpos=pos;
 
1123
      splits++;
 
1124
      VOID(_mi_pack_get_block_info(info, &info->bit_buff, &block_info,
 
1125
                                   &info->rec_buff, -1, start_recpos));
 
1126
      pos=block_info.filepos+block_info.rec_len;
 
1127
      if (block_info.rec_len < (uint) info->s->min_pack_length ||
 
1128
          block_info.rec_len > (uint) info->s->max_pack_length)
 
1129
      {
 
1130
        mi_check_print_error(param,
 
1131
                             "Found block with wrong recordlength: %d at %s",
 
1132
                             block_info.rec_len, llstr(start_recpos,llbuff));
 
1133
        got_error=1;
 
1134
        break;
 
1135
      }
 
1136
      if (_mi_read_cache(&param->read_cache,(uchar*) info->rec_buff,
 
1137
                        block_info.filepos, block_info.rec_len, READING_NEXT))
 
1138
        goto err;
 
1139
      if (_mi_pack_rec_unpack(info, &info->bit_buff, record,
 
1140
                              info->rec_buff, block_info.rec_len))
 
1141
      {
 
1142
        mi_check_print_error(param,"Found wrong record at %s",
 
1143
                             llstr(start_recpos,llbuff));
 
1144
        got_error=1;
 
1145
      }
 
1146
      if (static_row_size)
 
1147
        param->glob_crc+= mi_static_checksum(info,record);
 
1148
      else
 
1149
        param->glob_crc+= mi_checksum(info,record);
 
1150
      link_used+= (block_info.filepos - start_recpos);
 
1151
      used+= (pos-start_recpos);
1116
1152
    case BLOCK_RECORD:
1117
1153
      assert(0);                                /* Impossible */
1118
1154
    } /* switch */
1122
1158
      records++;
1123
1159
      if (param->testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0)
1124
1160
      {
1125
 
        printf("%s\r", llstr(records,llbuff)); fflush(stdout);
 
1161
        printf("%s\r", llstr(records,llbuff)); VOID(fflush(stdout));
1126
1162
      }
1127
1163
 
1128
1164
      /* Check if keys match the record */
1132
1168
      {
1133
1169
        if (mi_is_key_active(info->s->state.key_map, key))
1134
1170
        {
 
1171
          if(!(keyinfo->flag & HA_FULLTEXT))
1135
1172
          {
1136
 
            uint32_t key_length=_mi_make_key(info,key,info->lastkey,record,
 
1173
            uint key_length=_mi_make_key(info,key,info->lastkey,record,
1137
1174
                                         start_recpos);
1138
1175
            if (extend)
1139
1176
            {
1153
1190
              }
1154
1191
            }
1155
1192
            else
1156
 
              key_checksum[key]+=mi_byte_checksum((unsigned char*) info->lastkey,
 
1193
              key_checksum[key]+=mi_byte_checksum((uchar*) info->lastkey,
1157
1194
                                                  key_length);
1158
1195
          }
1159
1196
        }
1169
1206
  }
1170
1207
  if (param->testflag & T_WRITE_LOOP)
1171
1208
  {
1172
 
    fputs("          \r",stdout); fflush(stdout);
 
1209
    VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
1173
1210
  }
1174
1211
  if (records != info->state->records)
1175
1212
  {
1186
1223
  }
1187
1224
  else if (param->glob_crc != info->state->checksum &&
1188
1225
           (info->s->options &
1189
 
            (HA_OPTION_COMPRESS_RECORD)))
 
1226
            (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
1190
1227
  {
1191
1228
    mi_check_print_warning(param,
1192
1229
                           "Record checksum is not the same as checksum stored in the index file\n");
1196
1233
  {
1197
1234
    for (key=0 ; key < info->s->base.keys;  key++)
1198
1235
    {
1199
 
      if (key_checksum[key] != param->key_crc[key])
 
1236
      if (key_checksum[key] != param->key_crc[key] &&
 
1237
          !(info->s->keyinfo[key].flag & (HA_FULLTEXT | HA_SPATIAL)))
1200
1238
      {
1201
1239
        mi_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records",
1202
1240
                    key+1);
1262
1300
    printf("Lost space:   %12s    Linkdata:     %10s\n",
1263
1301
           llstr(empty,llbuff),llstr(link_used,llbuff2));
1264
1302
  }
1265
 
  free(mi_get_rec_buff_ptr(info, record));
 
1303
  my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
1266
1304
  return (error);
1267
1305
 err:
1268
 
  mi_check_print_error(param,"got error: %d when reading datafile at record: %s",errno, llstr(records,llbuff));
 
1306
  mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff));
1269
1307
 err2:
1270
 
  free(mi_get_rec_buff_ptr(info, record));
 
1308
  my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
1271
1309
  param->testflag|=T_RETRY_WITHOUT_QUICK;
1272
1310
  return(1);
1273
1311
} /* chk_data_link */
1313
1351
 
1314
1352
    However, there is an exception. Sometimes MySQL disables non-unique
1315
1353
    indexes when the table is empty (e.g. when copying a table in
1316
 
    drizzled::alter_table()). When enabling the non-unique indexes, they
 
1354
    mysql_alter_table()). When enabling the non-unique indexes, they
1317
1355
    are still empty. So there is no index block that can be lost. This
1318
1356
    optimization is implemented in this function.
1319
1357
 
1326
1364
    then recrate all indexes.
1327
1365
*/
1328
1366
 
1329
 
static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, bool force)
 
1367
static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force)
1330
1368
{
1331
1369
  MYISAM_SHARE *share= info->s;
1332
1370
  MI_STATE_INFO *state= &share->state;
1333
 
  uint32_t i;
 
1371
  uint i;
1334
1372
  int error;
1335
1373
 
1336
1374
  /*
1362
1400
        Flush dirty blocks of this index file from key cache and remove
1363
1401
        all blocks of this index file from key cache.
1364
1402
      */
1365
 
      error= flush_key_blocks(share->getKeyCache(), share->kfile,
 
1403
      error= flush_key_blocks(share->key_cache, share->kfile,
1366
1404
                              FLUSH_FORCE_WRITE);
1367
1405
      goto end;
1368
1406
    }
1375
1413
  }
1376
1414
 
1377
1415
  /* Remove all key blocks of this index file from key cache. */
1378
 
  if ((error= flush_key_blocks(share->getKeyCache(), share->kfile,
 
1416
  if ((error= flush_key_blocks(share->key_cache, share->kfile,
1379
1417
                               FLUSH_IGNORE_CHANGED)))
1380
 
    goto end;
 
1418
    goto end; /* purecov: inspected */
1381
1419
 
1382
1420
  /* Clear index root block pointers. */
1383
1421
  for (i= 0; i < share->base.keys; i++)
1406
1444
  int error,got_error;
1407
1445
  ha_rows start_records,new_header_length;
1408
1446
  my_off_t del;
1409
 
  int new_file;
 
1447
  File new_file;
1410
1448
  MYISAM_SHARE *share=info->s;
1411
1449
  char llbuff[22],llbuff2[22];
1412
1450
  SORT_INFO sort_info;
1413
1451
  MI_SORT_PARAM sort_param;
1414
1452
 
1415
 
  memset(&sort_info, 0, sizeof(sort_info));
1416
 
  memset(&sort_param, 0, sizeof(sort_param));
 
1453
  memset((char *)&sort_info, 0, sizeof(sort_info));
 
1454
  memset((char *)&sort_param, 0, sizeof(sort_param));
1417
1455
  start_records=info->state->records;
1418
1456
  new_header_length=(param->testflag & T_UNPACK) ? 0L :
1419
1457
    share->pack.header_length;
1428
1466
  }
1429
1467
  param->testflag|=T_REP; /* for easy checking */
1430
1468
 
1431
 
  if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
 
1469
  if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1432
1470
    param->testflag|=T_CALC_CHECKSUM;
1433
1471
 
1434
1472
  if (!param->using_global_keycache)
1435
 
    assert(0);
 
1473
    VOID(init_key_cache(dflt_key_cache, param->key_cache_block_size,
 
1474
                        param->use_buffers, 0, 0));
1436
1475
 
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)))
 
1476
  if (init_io_cache(&param->read_cache,info->dfile,
 
1477
                    (uint) param->read_buffer_length,
 
1478
                    READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
1438
1479
  {
1439
1480
    memset(&info->rec_cache, 0, sizeof(info->rec_cache));
1440
1481
    goto err;
1441
1482
  }
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
 
    {
 
1483
  if (!rep_quick)
 
1484
    if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
 
1485
                      WRITE_CACHE, new_header_length, 1,
 
1486
                      MYF(MY_WME | MY_WAIT_IF_FULL)))
1446
1487
      goto err;
1447
 
    }
1448
 
  }
1449
1488
  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))
 
1489
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
 
1490
      !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
1452
1491
  {
1453
1492
    mi_check_print_error(param, "Not enough memory for extra record");
1454
1493
    goto err;
1457
1496
  if (!rep_quick)
1458
1497
  {
1459
1498
    /* 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)
 
1499
    if ((new_file=my_raid_create(fn_format(param->temp_filename,
 
1500
                                           share->data_file_name, "",
 
1501
                                           DATA_TMP_EXT, 2+4),
 
1502
                                 0,param->tmpfile_createflag,
 
1503
                                 share->base.raid_type,
 
1504
                                 share->base.raid_chunks,
 
1505
                                 share->base.raid_chunksize,
 
1506
                                 MYF(0))) < 0)
1465
1507
    {
1466
1508
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
1467
 
                           param->temp_filename);
 
1509
                           param->temp_filename);
1468
1510
      goto err;
1469
1511
    }
1470
1512
    if (new_header_length &&
1471
1513
        filecopy(param,new_file,info->dfile,0L,new_header_length,
1472
 
                 "datafile-header"))
 
1514
                 "datafile-header"))
1473
1515
      goto err;
1474
1516
    info->s->state.dellink= HA_OFFSET_ERROR;
1475
1517
    info->rec_cache.file=new_file;
1485
1527
  sort_param.pos=sort_param.max_pos=share->pack.header_length;
1486
1528
  sort_param.filepos=new_header_length;
1487
1529
  param->read_cache.end_of_file=sort_info.filelength=
1488
 
    lseek(info->dfile,0L,SEEK_END);
 
1530
    my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
1489
1531
  sort_info.dupp=0;
1490
 
  sort_param.fix_datafile= (bool) (! rep_quick);
 
1532
  sort_param.fix_datafile= (my_bool) (! rep_quick);
1491
1533
  sort_param.master=1;
1492
1534
  sort_info.max_records= ~(ha_rows) 0;
1493
1535
 
1513
1555
  {
1514
1556
    if (writekeys(&sort_param))
1515
1557
    {
1516
 
      if (errno != HA_ERR_FOUND_DUPP_KEY)
 
1558
      if (my_errno != HA_ERR_FOUND_DUPP_KEY)
1517
1559
        goto err;
1518
1560
      mi_check_print_info(param,"Duplicate key %2d for record at %10s against new record at %10s",
1519
1561
                          info->errkey+1,
1521
1563
                          llstr(info->dupp_key_pos,llbuff2));
1522
1564
      if (param->testflag & T_VERBOSE)
1523
1565
      {
1524
 
        _mi_make_key(info,(uint) info->errkey,info->lastkey,
1525
 
                     sort_param.record,0L);
 
1566
        VOID(_mi_make_key(info,(uint) info->errkey,info->lastkey,
 
1567
                          sort_param.record,0L));
1526
1568
      }
1527
1569
      sort_info.dupp++;
1528
1570
      if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
1536
1578
    if (sort_write_record(&sort_param))
1537
1579
      goto err;
1538
1580
  }
1539
 
  if (error > 0 || write_data_suffix(&sort_info, (bool)!rep_quick) ||
 
1581
  if (error > 0 || write_data_suffix(&sort_info, (my_bool)!rep_quick) ||
1540
1582
      flush_io_cache(&info->rec_cache) || param->read_cache.error < 0)
1541
1583
    goto err;
1542
1584
 
1543
1585
  if (param->testflag & T_WRITE_LOOP)
1544
1586
  {
1545
 
    fputs("          \r",stdout); fflush(stdout);
 
1587
    VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
1546
1588
  }
1547
1589
  if (ftruncate(share->kfile, info->state->key_file_length))
1548
1590
  {
1549
1591
    mi_check_print_warning(param,
1550
1592
                           "Can't change size of indexfile, error: %d",
1551
 
                           errno);
 
1593
                           my_errno);
1552
1594
    goto err;
1553
1595
  }
1554
1596
 
1574
1616
 
1575
1617
  if (!rep_quick)
1576
1618
  {
1577
 
    internal::my_close(info->dfile,MYF(0));
 
1619
    my_close(info->dfile,MYF(0));
1578
1620
    info->dfile=new_file;
1579
1621
    info->state->data_file_length=sort_param.filepos;
1580
1622
    share->state.version=(ulong) time((time_t*) 0);     /* Force reopen */
1607
1649
    /* Replace the actual file with the temporary file */
1608
1650
    if (new_file >= 0)
1609
1651
    {
1610
 
      internal::my_close(new_file,MYF(0));
 
1652
      my_close(new_file,MYF(0));
1611
1653
      info->dfile=new_file= -1;
1612
1654
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
1613
1655
                            DATA_TMP_EXT, share->base.raid_chunks,
1620
1662
  if (got_error)
1621
1663
  {
1622
1664
    if (! param->error_printed)
1623
 
      mi_check_print_error(param,"%d for record at pos %s",errno,
 
1665
      mi_check_print_error(param,"%d for record at pos %s",my_errno,
1624
1666
                  llstr(sort_param.start_recpos,llbuff));
1625
1667
    if (new_file >= 0)
1626
1668
    {
1627
 
      internal::my_close(new_file,MYF(0));
1628
 
      my_delete(param->temp_filename, MYF(MY_WME));
 
1669
      VOID(my_close(new_file,MYF(0)));
 
1670
      VOID(my_raid_delete(param->temp_filename,info->s->base.raid_chunks,
 
1671
                          MYF(MY_WME)));
1629
1672
      info->rec_cache.file=-1; /* don't flush data to new_file, it's closed */
1630
1673
    }
1631
1674
    mi_mark_crashed_on_repair(info);
1632
1675
  }
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();
 
1676
  my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff),
 
1677
                            MYF(MY_ALLOW_ZERO_PTR));
 
1678
  my_free(mi_get_rec_buff_ptr(info, sort_param.record),
 
1679
          MYF(MY_ALLOW_ZERO_PTR));
 
1680
  my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
 
1681
  VOID(end_io_cache(&param->read_cache));
1645
1682
  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)
 
1683
  VOID(end_io_cache(&info->rec_cache));
 
1684
  got_error|=flush_blocks(param, share->key_cache, share->kfile);
 
1685
  if (!got_error && param->testflag & T_UNPACK)
1649
1686
  {
1650
 
    share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
 
1687
    share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
1651
1688
    share->pack.header_length=0;
1652
1689
    share->data_file_type=sort_info.new_data_file_type;
1653
1690
  }
1661
1698
 
1662
1699
static int writekeys(MI_SORT_PARAM *sort_param)
1663
1700
{
1664
 
  register uint32_t i;
1665
 
  unsigned char    *key;
 
1701
  register uint i;
 
1702
  uchar    *key;
1666
1703
  MI_INFO  *info=   sort_param->sort_info->info;
1667
 
  unsigned char    *buff=   sort_param->record;
 
1704
  uchar    *buff=   sort_param->record;
1668
1705
  my_off_t filepos= sort_param->filepos;
1669
1706
 
1670
1707
  key=info->lastkey+info->s->base.max_key_length;
1673
1710
    if (mi_is_key_active(info->s->state.key_map, i))
1674
1711
    {
1675
1712
      {
1676
 
        uint32_t key_length=_mi_make_key(info,i,key,buff,filepos);
 
1713
        uint key_length=_mi_make_key(info,i,key,buff,filepos);
1677
1714
        if (_mi_ck_write(info,i,key,key_length))
1678
1715
          goto err;
1679
1716
      }
1682
1719
  return(0);
1683
1720
 
1684
1721
 err:
1685
 
  if (errno == HA_ERR_FOUND_DUPP_KEY)
 
1722
  if (my_errno == HA_ERR_FOUND_DUPP_KEY)
1686
1723
  {
1687
1724
    info->errkey=(int) i;                       /* This key was found */
1688
1725
    while ( i-- > 0 )
1690
1727
      if (mi_is_key_active(info->s->state.key_map, i))
1691
1728
      {
1692
1729
        {
1693
 
          uint32_t key_length=_mi_make_key(info,i,key,buff,filepos);
 
1730
          uint key_length=_mi_make_key(info,i,key,buff,filepos);
1694
1731
          if (_mi_ck_delete(info,i,key,key_length))
1695
1732
            break;
1696
1733
        }
1706
1743
 
1707
1744
        /* Change all key-pointers that points to a records */
1708
1745
 
1709
 
int movepoint(register MI_INFO *info, unsigned char *record, my_off_t oldpos,
1710
 
              my_off_t newpos, uint32_t prot_key)
 
1746
int movepoint(register MI_INFO *info, uchar *record, my_off_t oldpos,
 
1747
              my_off_t newpos, uint prot_key)
1711
1748
{
1712
 
  register uint32_t i;
1713
 
  unsigned char *key;
1714
 
  uint32_t key_length;
 
1749
  register uint i;
 
1750
  uchar *key;
 
1751
  uint key_length;
1715
1752
 
1716
1753
  key=info->lastkey+info->s->base.max_key_length;
1717
1754
  for (i=0 ; i < info->s->base.keys; i++)
1721
1758
      key_length=_mi_make_key(info,i,key,record,oldpos);
1722
1759
      if (info->s->keyinfo[i].flag & HA_NOSAME)
1723
1760
      {                                 /* Change pointer direct */
1724
 
        uint32_t nod_flag;
 
1761
        uint nod_flag;
1725
1762
        MI_KEYDEF *keyinfo;
1726
1763
        keyinfo=info->s->keyinfo+i;
1727
1764
        if (_mi_search(info,keyinfo,key,USE_WHOLE_KEY,
1751
1788
 
1752
1789
        /* Tell system that we want all memory for our cache */
1753
1790
 
1754
 
void lock_memory(MI_CHECK *)
 
1791
void lock_memory(MI_CHECK *param __attribute__((unused)))
1755
1792
{
 
1793
#ifdef SUN_OS                           /* Key-cacheing thrases on sun 4.1 */
 
1794
  if (param->opt_lock_memory)
 
1795
  {
 
1796
    int success = mlockall(MCL_CURRENT);        /* or plock(DATLOCK); */
 
1797
    if (geteuid() == 0 && success != 0)
 
1798
      mi_check_print_warning(param,
 
1799
                             "Failed to lock memory. errno %d",my_errno);
 
1800
  }
 
1801
#endif
1756
1802
} /* lock_memory */
1757
1803
 
1758
1804
 
1759
1805
        /* Flush all changed blocks to disk */
1760
1806
 
1761
 
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, int file)
 
1807
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file)
1762
1808
{
1763
1809
  if (flush_key_blocks(key_cache, file, FLUSH_RELEASE))
1764
1810
  {
1765
 
    mi_check_print_error(param,"%d when trying to write bufferts",errno);
 
1811
    mi_check_print_error(param,"%d when trying to write bufferts",my_errno);
1766
1812
    return(1);
1767
1813
  }
1768
1814
  if (!param->using_global_keycache)
1775
1821
 
1776
1822
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
1777
1823
{
1778
 
  register uint32_t key;
 
1824
  register uint key;
1779
1825
  register MI_KEYDEF *keyinfo;
1780
 
  int new_file;
 
1826
  File new_file;
1781
1827
  my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
1782
 
  uint32_t r_locks,w_locks;
 
1828
  uint r_locks,w_locks;
1783
1829
  int old_lock;
1784
1830
  MYISAM_SHARE *share=info->s;
1785
1831
  MI_STATE_INFO old_state;
1792
1838
    printf("- Sorting index for MyISAM-table '%s'\n",name);
1793
1839
 
1794
1840
  /* 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,
 
1841
  fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32);
 
1842
  if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename,
1797
1843
                                    "", INDEX_TMP_EXT,2+4),
1798
1844
                          0,param->tmpfile_createflag,MYF(0))) <= 0)
1799
1845
  {
1824
1870
  }
1825
1871
 
1826
1872
  /* Flush key cache for this file if we are calling this outside myisamchk */
1827
 
  flush_key_blocks(share->getKeyCache(), share->kfile, FLUSH_IGNORE_CHANGED);
 
1873
  flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED);
1828
1874
 
1829
1875
  share->state.version=(ulong) time((time_t*) 0);
1830
1876
  old_state= share->state;                      /* save state if not stored */
1835
1881
        /* Put same locks as old file */
1836
1882
  share->r_locks= share->w_locks= share->tot_locks= 0;
1837
1883
  (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
1838
 
  internal::my_close(share->kfile,MYF(MY_WME));
 
1884
  VOID(my_close(share->kfile,MYF(MY_WME)));
1839
1885
  share->kfile = -1;
1840
 
  internal::my_close(new_file,MYF(MY_WME));
 
1886
  VOID(my_close(new_file,MYF(MY_WME)));
1841
1887
  if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1842
1888
                        MYF(0)) ||
1843
1889
      mi_open_keyfile(share))
1861
1907
  return(0);
1862
1908
 
1863
1909
err:
1864
 
  internal::my_close(new_file,MYF(MY_WME));
 
1910
  VOID(my_close(new_file,MYF(MY_WME)));
1865
1911
err2:
1866
 
  my_delete(param->temp_filename,MYF(MY_WME));
 
1912
  VOID(my_delete(param->temp_filename,MYF(MY_WME)));
1867
1913
  return(-1);
1868
1914
} /* mi_sort_index */
1869
1915
 
1871
1917
         /* Sort records recursive using one index */
1872
1918
 
1873
1919
static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
1874
 
                          my_off_t pagepos, int new_file)
 
1920
                          my_off_t pagepos, File new_file)
1875
1921
{
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];
 
1922
  uint length,nod_flag,used_length, key_length;
 
1923
  uchar *buff,*keypos,*endpos;
 
1924
  uchar key[HA_MAX_POSSIBLE_KEY_BUFF];
1879
1925
  my_off_t new_page_pos,next_page;
1880
1926
  char llbuff[22];
1881
1927
 
1882
1928
  new_page_pos=param->new_file_pos;
1883
1929
  param->new_file_pos+=keyinfo->block_length;
1884
1930
 
1885
 
  if (!(buff=(unsigned char*) malloc(keyinfo->block_length)))
 
1931
  if (!(buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1886
1932
  {
1887
1933
    mi_check_print_error(param,"Not enough memory for key block");
1888
1934
    return(-1);
1893
1939
                llstr(pagepos,llbuff));
1894
1940
    goto err;
1895
1941
  }
1896
 
  if ((nod_flag=mi_test_if_nod(buff)))
 
1942
  if ((nod_flag=mi_test_if_nod(buff)) || keyinfo->flag & HA_FULLTEXT)
1897
1943
  {
1898
1944
    used_length=mi_getint(buff);
1899
1945
    keypos=buff+2+nod_flag;
1918
1964
 
1919
1965
  /* Fill block with zero and write it to the new index file */
1920
1966
  length=mi_getint(buff);
1921
 
  memset(buff+length, 0, keyinfo->block_length-length);
1922
 
  if (my_pwrite(new_file,(unsigned char*) buff,(uint) keyinfo->block_length,
 
1967
  memset((uchar*) buff+length, 0, keyinfo->block_length-length);
 
1968
  if (my_pwrite(new_file,(uchar*) buff,(uint) keyinfo->block_length,
1923
1969
                new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
1924
1970
  {
1925
 
    mi_check_print_error(param,"Can't write indexblock, error: %d",errno);
 
1971
    mi_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
1926
1972
    goto err;
1927
1973
  }
1928
 
  free(buff);
 
1974
  my_afree((uchar*) buff);
1929
1975
  return(0);
1930
1976
err:
1931
 
  free(buff);
 
1977
  my_afree((uchar*) buff);
1932
1978
  return(1);
1933
1979
} /* sort_one_index */
1934
1980
 
1944
1990
 
1945
1991
int change_to_newfile(const char * filename, const char * old_ext,
1946
1992
                      const char * new_ext,
1947
 
                      uint32_t raid_chunks,
 
1993
                      uint raid_chunks __attribute__((unused)),
1948
1994
                      myf MyFlags)
1949
1995
{
1950
 
  (void)raid_chunks;
1951
1996
  char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
1952
1997
  /* Get real path to filename */
1953
 
  (void) internal::fn_format(old_filename,filename,"",old_ext,2+4+32);
 
1998
  (void) fn_format(old_filename,filename,"",old_ext,2+4+32);
1954
1999
  return my_redel(old_filename,
1955
 
                  internal::fn_format(new_filename,old_filename,"",new_ext,2+4),
 
2000
                  fn_format(new_filename,old_filename,"",new_ext,2+4),
1956
2001
                  MYF(MY_WME | MY_LINK_WARNING | MyFlags));
1957
2002
} /* change_to_newfile */
1958
2003
 
1960
2005
 
1961
2006
        /* Copy a block between two files */
1962
2007
 
1963
 
int filecopy(MI_CHECK *param, int to,int from,my_off_t start,
 
2008
int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
1964
2009
             my_off_t length, const char *type)
1965
2010
{
1966
2011
  char tmp_buff[IO_SIZE],*buff;
1967
2012
  ulong buff_length;
1968
2013
 
1969
 
  buff_length=(ulong) min(param->write_buffer_length, (size_t)length);
1970
 
  if (!(buff=(char *)malloc(buff_length)))
 
2014
  buff_length=(ulong) min(param->write_buffer_length,length);
 
2015
  if (!(buff=my_malloc(buff_length,MYF(0))))
1971
2016
  {
1972
2017
    buff=tmp_buff; buff_length=IO_SIZE;
1973
2018
  }
1974
2019
 
1975
 
  lseek(from,start,SEEK_SET);
 
2020
  VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
1976
2021
  while (length > buff_length)
1977
2022
  {
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))
 
2023
    if (my_read(from,(uchar*) buff,buff_length,MYF(MY_NABP)) ||
 
2024
        my_write(to,(uchar*) buff,buff_length,param->myf_rw))
1980
2025
      goto err;
1981
2026
    length-= buff_length;
1982
2027
  }
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))
 
2028
  if (my_read(from,(uchar*) buff,(uint) length,MYF(MY_NABP)) ||
 
2029
      my_write(to,(uchar*) buff,(uint) length,param->myf_rw))
1985
2030
    goto err;
1986
2031
  if (buff != tmp_buff)
1987
 
    free(buff);
 
2032
    my_free(buff,MYF(0));
1988
2033
  return(0);
1989
2034
err:
1990
2035
  if (buff != tmp_buff)
1991
 
    free(buff);
 
2036
    my_free(buff,MYF(0));
1992
2037
  mi_check_print_error(param,"Can't copy %s to tempfile, error %d",
1993
 
                       type,errno);
 
2038
                       type,my_errno);
1994
2039
  return(1);
1995
2040
}
1996
2041
 
2014
2059
                      const char * name, int rep_quick)
2015
2060
{
2016
2061
  int got_error;
2017
 
  uint32_t i;
 
2062
  uint i;
2018
2063
  ulong length;
2019
2064
  ha_rows start_records;
2020
2065
  my_off_t new_header_length,del;
2021
 
  int new_file;
 
2066
  File new_file;
2022
2067
  MI_SORT_PARAM sort_param;
2023
2068
  MYISAM_SHARE *share=info->s;
2024
2069
  HA_KEYSEG *keyseg;
2039
2084
  }
2040
2085
  param->testflag|=T_REP; /* for easy checking */
2041
2086
 
2042
 
  if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
 
2087
  if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
2043
2088
    param->testflag|=T_CALC_CHECKSUM;
2044
2089
 
2045
 
  memset(&sort_info, 0, sizeof(sort_info));
2046
 
  memset(&sort_param, 0, sizeof(sort_param));
 
2090
  memset((char*)&sort_info, 0, sizeof(sort_info));
 
2091
  memset((char *)&sort_param, 0, sizeof(sort_param));
2047
2092
  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
 
  {
 
2093
        alloc_key_blocks(param,
 
2094
                         (uint) param->sort_key_blocks,
 
2095
                         share->base.max_key_block_length))
 
2096
      || init_io_cache(&param->read_cache,info->dfile,
 
2097
                       (uint) param->read_buffer_length,
 
2098
                       READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
 
2099
      (! rep_quick &&
 
2100
       init_io_cache(&info->rec_cache,info->dfile,
 
2101
                     (uint) param->write_buffer_length,
 
2102
                     WRITE_CACHE,new_header_length,1,
 
2103
                     MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)))
2052
2104
    goto err;
2053
 
  }
2054
2105
  sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
2055
2106
  info->opt_flag|=WRITE_CACHE_USED;
2056
2107
  info->rec_cache.file=info->dfile;             /* for sort_delete_record */
2057
2108
 
2058
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.record) ||
2059
 
      !mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.rec_buff))
 
2109
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
 
2110
      !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
2060
2111
  {
2061
2112
    mi_check_print_error(param, "Not enough memory for extra record");
2062
2113
    goto err;
2064
2115
  if (!rep_quick)
2065
2116
  {
2066
2117
    /* 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)
 
2118
    if ((new_file=my_raid_create(fn_format(param->temp_filename,
 
2119
                                           share->data_file_name, "",
 
2120
                                           DATA_TMP_EXT, 2+4),
 
2121
                                 0,param->tmpfile_createflag,
 
2122
                                 share->base.raid_type,
 
2123
                                 share->base.raid_chunks,
 
2124
                                 share->base.raid_chunksize,
 
2125
                                 MYF(0))) < 0)
2072
2126
    {
2073
2127
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
2074
 
                           param->temp_filename);
 
2128
                           param->temp_filename);
2075
2129
      goto err;
2076
2130
    }
2077
2131
    if (new_header_length &&
2106
2160
  sort_info.dupp=0;
2107
2161
  sort_info.buff=0;
2108
2162
  param->read_cache.end_of_file=sort_info.filelength=
2109
 
    lseek(param->read_cache.file,0L,SEEK_END);
 
2163
    my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
2110
2164
 
2111
2165
  sort_param.wordlist=NULL;
2112
2166
 
2121
2175
     (ha_rows) (sort_info.filelength/length+1));
2122
2176
  sort_param.key_cmp=sort_key_cmp;
2123
2177
  sort_param.lock_in_memory=lock_memory;
 
2178
  sort_param.tmpdir=param->tmpdir;
2124
2179
  sort_param.sort_info=&sort_info;
2125
 
  sort_param.fix_datafile= (bool) (! rep_quick);
 
2180
  sort_param.fix_datafile= (my_bool) (! rep_quick);
2126
2181
  sort_param.master =1;
2127
 
 
 
2182
  
2128
2183
  del=info->state->del;
2129
2184
  param->glob_crc=0;
2130
2185
  if (param->testflag & T_CALC_CHECKSUM)
2144
2199
    if (! mi_is_key_active(key_map, sort_param.key))
2145
2200
    {
2146
2201
      /* Remember old statistics for key */
2147
 
      assert(rec_per_key_part >= param->rec_per_key_part);
2148
 
      memcpy(rec_per_key_part,
2149
 
             (share->state.rec_per_key_part +
2150
 
              (rec_per_key_part - param->rec_per_key_part)),
 
2202
      memcpy((char*) rec_per_key_part,
 
2203
             (char*) (share->state.rec_per_key_part +
 
2204
                      (uint) (rec_per_key_part - param->rec_per_key_part)),
2151
2205
             sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
2152
2206
      continue;
2153
2207
    }
2156
2210
      printf ("- Fixing index %d\n",sort_param.key+1);
2157
2211
    sort_param.max_pos=sort_param.pos=share->pack.header_length;
2158
2212
    keyseg=sort_param.seg;
2159
 
    memset(sort_param.unique, 0, sizeof(sort_param.unique));
 
2213
    memset((char*) sort_param.unique, 0, sizeof(sort_param.unique));
2160
2214
    sort_param.key_length=share->rec_reflength;
2161
2215
    for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++)
2162
2216
    {
2177
2231
    }
2178
2232
 
2179
2233
    if (_create_index_by_sort(&sort_param,
2180
 
                              (bool) (!(param->testflag & T_VERBOSE)),
 
2234
                              (my_bool) (!(param->testflag & T_VERBOSE)),
2181
2235
                              (uint) param->sort_buffer_length))
2182
2236
    {
2183
2237
      param->retry_repair=1;
2185
2239
    }
2186
2240
    /* No need to calculate checksum again. */
2187
2241
    sort_param.calc_checksum= 0;
2188
 
    sort_param.wordroot.free_root(MYF(0));
 
2242
    free_root(&sort_param.wordroot, MYF(0));
2189
2243
 
2190
2244
    /* Set for next loop */
2191
2245
    sort_info.max_records= (ha_rows) info->state->records;
2201
2255
    if (sort_param.fix_datafile)
2202
2256
    {
2203
2257
      param->read_cache.end_of_file=sort_param.filepos;
2204
 
      if (write_data_suffix(&sort_info, 1) || info->rec_cache.end_io_cache())
2205
 
      {
 
2258
      if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
2206
2259
        goto err;
2207
 
      }
2208
2260
      if (param->testflag & T_SAFE_REPAIR)
2209
2261
      {
2210
2262
        /* Don't repair if we loosed more than one row */
2218
2270
        sort_param.filepos;
2219
2271
      /* Only whole records */
2220
2272
      share->state.version=(ulong) time((time_t*) 0);
2221
 
      internal::my_close(info->dfile,MYF(0));
 
2273
      my_close(info->dfile,MYF(0));
2222
2274
      info->dfile=new_file;
2223
2275
      share->data_file_type=sort_info.new_data_file_type;
2224
2276
      share->pack.header_length=(ulong) new_header_length;
2228
2280
      info->state->data_file_length=sort_param.max_pos;
2229
2281
 
2230
2282
    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);
 
2283
    reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
 
2284
                    1,1);
2232
2285
  }
2233
2286
 
2234
2287
  if (param->testflag & T_WRITE_LOOP)
2235
2288
  {
2236
 
    fputs("          \r",stdout); fflush(stdout);
 
2289
    VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
2237
2290
  }
2238
2291
 
2239
2292
  if (rep_quick && del+sort_info.dupp != info->state->del)
2260
2313
      if (ftruncate(info->dfile, skr))
2261
2314
        mi_check_print_warning(param,
2262
2315
                               "Can't change size of datafile,  error: %d",
2263
 
                               errno);
 
2316
                               my_errno);
2264
2317
  }
2265
2318
  if (param->testflag & T_CALC_CHECKSUM)
2266
2319
    info->state->checksum=param->glob_crc;
2268
2321
  if (ftruncate(share->kfile, info->state->key_file_length))
2269
2322
    mi_check_print_warning(param,
2270
2323
                           "Can't change size of indexfile, error: %d",
2271
 
                           errno);
 
2324
                           my_errno);
2272
2325
 
2273
2326
  if (!(param->testflag & T_SILENT))
2274
2327
  {
2285
2338
    memcpy( &share->state.state, info->state, sizeof(*info->state));
2286
2339
 
2287
2340
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;
 
2341
  got_error|= flush_blocks(param, share->key_cache, share->kfile);
 
2342
  VOID(end_io_cache(&info->rec_cache));
 
2343
  if (!got_error)
 
2344
  {
 
2345
    /* Replace the actual file with the temporary file */
 
2346
    if (new_file >= 0)
 
2347
    {
 
2348
      my_close(new_file,MYF(0));
 
2349
      info->dfile=new_file= -1;
 
2350
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
 
2351
                            DATA_TMP_EXT, share->base.raid_chunks,
 
2352
                            (param->testflag & T_BACKUP_DATA ?
 
2353
                             MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
 
2354
          mi_open_datafile(info,share,-1))
 
2355
        got_error=1;
 
2356
    }
 
2357
  }
 
2358
  if (got_error)
 
2359
  {
 
2360
    if (! param->error_printed)
 
2361
      mi_check_print_error(param,"%d when fixing table",my_errno);
 
2362
    if (new_file >= 0)
 
2363
    {
 
2364
      VOID(my_close(new_file,MYF(0)));
 
2365
      VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks,
 
2366
                          MYF(MY_WME)));
 
2367
      if (info->dfile == new_file)
 
2368
        info->dfile= -1;
 
2369
    }
 
2370
    mi_mark_crashed_on_repair(info);
 
2371
  }
 
2372
  else if (key_map == share->state.key_map)
 
2373
    share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
 
2374
  share->state.changed|=STATE_NOT_SORTED_PAGES;
 
2375
 
 
2376
  my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff),
 
2377
                            MYF(MY_ALLOW_ZERO_PTR));
 
2378
  my_free(mi_get_rec_buff_ptr(info, sort_param.record),
 
2379
          MYF(MY_ALLOW_ZERO_PTR));
 
2380
  my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
 
2381
  my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
 
2382
  VOID(end_io_cache(&param->read_cache));
 
2383
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
 
2384
  if (!got_error && (param->testflag & T_UNPACK))
 
2385
  {
 
2386
    share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
 
2387
    share->pack.header_length=0;
 
2388
  }
 
2389
  return(got_error);
 
2390
}
 
2391
 
 
2392
/*
 
2393
  Threaded repair of table using sorting
 
2394
 
 
2395
  SYNOPSIS
 
2396
    mi_repair_parallel()
 
2397
    param               Repair parameters
 
2398
    info                MyISAM handler to repair
 
2399
    name                Name of table (for warnings)
 
2400
    rep_quick           set to <> 0 if we should not change data file
 
2401
 
 
2402
  DESCRIPTION
 
2403
    Same as mi_repair_by_sort but do it multithreaded
 
2404
    Each key is handled by a separate thread.
 
2405
    TODO: make a number of threads a parameter
 
2406
 
 
2407
    In parallel repair we use one thread per index. There are two modes:
 
2408
 
 
2409
    Quick
 
2410
 
 
2411
      Only the indexes are rebuilt. All threads share a read buffer.
 
2412
      Every thread that needs fresh data in the buffer enters the shared
 
2413
      cache lock. The last thread joining the lock reads the buffer from
 
2414
      the data file and wakes all other threads.
 
2415
 
 
2416
    Non-quick
 
2417
 
 
2418
      The data file is rebuilt and all indexes are rebuilt to point to
 
2419
      the new record positions. One thread is the master thread. It
 
2420
      reads from the old data file and writes to the new data file. It
 
2421
      also creates one of the indexes. The other threads read from a
 
2422
      buffer which is filled by the master. If they need fresh data,
 
2423
      they enter the shared cache lock. If the masters write buffer is
 
2424
      full, it flushes it to the new data file and enters the shared
 
2425
      cache lock too. When all threads joined in the lock, the master
 
2426
      copies its write buffer to the read buffer for the other threads
 
2427
      and wakes them.
 
2428
 
 
2429
  RESULT
 
2430
    0   ok
 
2431
    <>0 Error
 
2432
*/
 
2433
 
 
2434
int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
 
2435
                        const char * name, int rep_quick)
 
2436
{
 
2437
  int got_error;
 
2438
  uint i,key, total_key_length, istep;
 
2439
  ulong rec_length;
 
2440
  ha_rows start_records;
 
2441
  my_off_t new_header_length,del;
 
2442
  File new_file;
 
2443
  MI_SORT_PARAM *sort_param=0;
 
2444
  MYISAM_SHARE *share=info->s;
 
2445
  ulong   *rec_per_key_part;
 
2446
  HA_KEYSEG *keyseg;
 
2447
  char llbuff[22];
 
2448
  IO_CACHE new_data_cache; /* For non-quick repair. */
 
2449
  IO_CACHE_SHARE io_share;
 
2450
  SORT_INFO sort_info;
 
2451
  uint64_t key_map= 0;
 
2452
  pthread_attr_t thr_attr;
 
2453
  ulong max_pack_reclength;
 
2454
 
 
2455
  start_records=info->state->records;
 
2456
  got_error=1;
 
2457
  new_file= -1;
 
2458
  new_header_length=(param->testflag & T_UNPACK) ? 0 :
 
2459
    share->pack.header_length;
 
2460
  if (!(param->testflag & T_SILENT))
 
2461
  {
 
2462
    printf("- parallel recovering (with sort) MyISAM-table '%s'\n",name);
 
2463
    printf("Data records: %s\n", llstr(start_records,llbuff));
 
2464
  }
 
2465
  param->testflag|=T_REP; /* for easy checking */
 
2466
 
 
2467
  if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
 
2468
    param->testflag|=T_CALC_CHECKSUM;
 
2469
 
 
2470
  /*
 
2471
    Quick repair (not touching data file, rebuilding indexes):
 
2472
    {
 
2473
      Read  cache is (MI_CHECK *param)->read_cache using info->dfile.
 
2474
    }
 
2475
 
 
2476
    Non-quick repair (rebuilding data file and indexes):
 
2477
    {
 
2478
      Master thread:
 
2479
 
 
2480
        Read  cache is (MI_CHECK *param)->read_cache using info->dfile.
 
2481
        Write cache is (MI_INFO   *info)->rec_cache  using new_file.
 
2482
 
 
2483
      Slave threads:
 
2484
 
 
2485
        Read  cache is new_data_cache synced to master rec_cache.
 
2486
 
 
2487
      The final assignment of the filedescriptor for rec_cache is done
 
2488
      after the cache creation.
 
2489
 
 
2490
      Don't check file size on new_data_cache, as the resulting file size
 
2491
      is not known yet.
 
2492
 
 
2493
      As rec_cache and new_data_cache are synced, write_buffer_length is
 
2494
      used for the read cache 'new_data_cache'. Both start at the same
 
2495
      position 'new_header_length'.
 
2496
    }
 
2497
  */
 
2498
  memset((char*)&sort_info, 0, sizeof(sort_info));
 
2499
  /* Initialize pthread structures before goto err. */
 
2500
  pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
 
2501
  pthread_cond_init(&sort_info.cond, 0);
 
2502
 
 
2503
  if (!(sort_info.key_block=
 
2504
        alloc_key_blocks(param, (uint) param->sort_key_blocks,
 
2505
                         share->base.max_key_block_length)) ||
 
2506
      init_io_cache(&param->read_cache, info->dfile,
 
2507
                    (uint) param->read_buffer_length,
 
2508
                    READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) ||
 
2509
      (!rep_quick &&
 
2510
       (init_io_cache(&info->rec_cache, info->dfile,
 
2511
                      (uint) param->write_buffer_length,
 
2512
                      WRITE_CACHE, new_header_length, 1,
 
2513
                      MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) ||
 
2514
        init_io_cache(&new_data_cache, -1,
 
2515
                      (uint) param->write_buffer_length,
 
2516
                      READ_CACHE, new_header_length, 1,
 
2517
                      MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))))
 
2518
    goto err;
 
2519
  sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
 
2520
  info->opt_flag|=WRITE_CACHE_USED;
 
2521
  info->rec_cache.file=info->dfile;         /* for sort_delete_record */
 
2522
 
 
2523
  if (!rep_quick)
 
2524
  {
 
2525
    /* Get real path for data file */
 
2526
    if ((new_file=my_raid_create(fn_format(param->temp_filename,
 
2527
                                           share->data_file_name, "",
 
2528
                                           DATA_TMP_EXT,
 
2529
                                           2+4),
 
2530
                                 0,param->tmpfile_createflag,
 
2531
                                 share->base.raid_type,
 
2532
                                 share->base.raid_chunks,
 
2533
                                 share->base.raid_chunksize,
 
2534
                                 MYF(0))) < 0)
 
2535
    {
 
2536
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
 
2537
                           param->temp_filename);
 
2538
      goto err;
 
2539
    }
 
2540
    if (new_header_length &&
 
2541
        filecopy(param, new_file,info->dfile,0L,new_header_length,
 
2542
                 "datafile-header"))
 
2543
      goto err;
 
2544
    if (param->testflag & T_UNPACK)
 
2545
    {
 
2546
      share->options&= ~HA_OPTION_COMPRESS_RECORD;
 
2547
      mi_int2store(share->state.header.options,share->options);
 
2548
    }
 
2549
    share->state.dellink= HA_OFFSET_ERROR;
 
2550
    info->rec_cache.file=new_file;
 
2551
  }
 
2552
 
 
2553
  info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
 
2554
 
 
2555
  /* Optionally drop indexes and optionally modify the key_map. */
 
2556
  mi_drop_all_indexes(param, info, false);
 
2557
  key_map= share->state.key_map;
 
2558
  if (param->testflag & T_CREATE_MISSING_KEYS)
 
2559
  {
 
2560
    /* Invert the copied key_map to recreate all disabled indexes. */
 
2561
    key_map= ~key_map;
 
2562
  }
 
2563
 
 
2564
  sort_info.info=info;
 
2565
  sort_info.param = param;
 
2566
 
 
2567
  set_data_file_type(&sort_info, share);
 
2568
  sort_info.dupp=0;
 
2569
  sort_info.buff=0;
 
2570
  param->read_cache.end_of_file=sort_info.filelength=
 
2571
    my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
 
2572
 
 
2573
  if (share->data_file_type == DYNAMIC_RECORD)
 
2574
    rec_length=max(share->base.min_pack_length+1,share->base.min_block_length);
 
2575
  else if (share->data_file_type == COMPRESSED_RECORD)
 
2576
    rec_length=share->base.min_block_length;
 
2577
  else
 
2578
    rec_length=share->base.pack_reclength;
 
2579
  /*
 
2580
    +1 below is required hack for parallel repair mode.
 
2581
    The info->state->records value, that is compared later
 
2582
    to sort_info.max_records and cannot exceed it, is
 
2583
    increased in sort_key_write. In mi_repair_by_sort, sort_key_write
 
2584
    is called after sort_key_read, where the comparison is performed,
 
2585
    but in parallel mode master thread can call sort_key_write
 
2586
    before some other repair thread calls sort_key_read.
 
2587
    Furthermore I'm not even sure +1 would be enough.
 
2588
    May be sort_info.max_records shold be always set to max value in
 
2589
    parallel mode.
 
2590
  */
 
2591
  sort_info.max_records=
 
2592
    ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records + 1:
 
2593
     (ha_rows) (sort_info.filelength/rec_length+1));
 
2594
 
 
2595
  del=info->state->del;
 
2596
  param->glob_crc=0;
 
2597
  /* for compressed tables */
 
2598
  max_pack_reclength= share->base.pack_reclength;
 
2599
  if (share->options & HA_OPTION_COMPRESS_RECORD)
 
2600
    set_if_bigger(max_pack_reclength, share->max_pack_length);
 
2601
  if (!(sort_param=(MI_SORT_PARAM *)
 
2602
        my_malloc((uint) share->base.keys *
 
2603
                  (sizeof(MI_SORT_PARAM) + max_pack_reclength),
 
2604
                  MYF(MY_ZEROFILL))))
 
2605
  {
 
2606
    mi_check_print_error(param,"Not enough memory for key!");
 
2607
    goto err;
 
2608
  }
 
2609
  total_key_length=0;
 
2610
  rec_per_key_part= param->rec_per_key_part;
 
2611
  info->state->records=info->state->del=share->state.split=0;
 
2612
  info->state->empty=0;
 
2613
 
 
2614
  for (i=key=0, istep=1 ; key < share->base.keys ;
 
2615
       rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
 
2616
  {
 
2617
    sort_param[i].key=key;
 
2618
    sort_param[i].keyinfo=share->keyinfo+key;
 
2619
    sort_param[i].seg=sort_param[i].keyinfo->seg;
 
2620
    /*
 
2621
      Skip this index if it is marked disabled in the copied
 
2622
      (and possibly inverted) key_map.
 
2623
    */
 
2624
    if (! mi_is_key_active(key_map, key))
 
2625
    {
 
2626
      /* Remember old statistics for key */
 
2627
      memcpy((char*) rec_per_key_part,
 
2628
             (char*) (share->state.rec_per_key_part+
 
2629
                      (uint) (rec_per_key_part - param->rec_per_key_part)),
 
2630
             sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
 
2631
      istep=0;
 
2632
      continue;
 
2633
    }
 
2634
    istep=1;
 
2635
    if ((!(param->testflag & T_SILENT)))
 
2636
      printf ("- Fixing index %d\n",key+1);
 
2637
    {
 
2638
      sort_param[i].key_read=sort_key_read;
 
2639
      sort_param[i].key_write=sort_key_write;
 
2640
    }
 
2641
    sort_param[i].key_cmp=sort_key_cmp;
 
2642
    sort_param[i].lock_in_memory=lock_memory;
 
2643
    sort_param[i].tmpdir=param->tmpdir;
 
2644
    sort_param[i].sort_info=&sort_info;
 
2645
    sort_param[i].master=0;
 
2646
    sort_param[i].fix_datafile=0;
 
2647
    sort_param[i].calc_checksum= 0;
 
2648
 
 
2649
    sort_param[i].filepos=new_header_length;
 
2650
    sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
 
2651
 
 
2652
    sort_param[i].record= (((uchar *)(sort_param+share->base.keys))+
 
2653
                           (max_pack_reclength * i));
 
2654
    if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff))
 
2655
    {
 
2656
      mi_check_print_error(param,"Not enough memory!");
 
2657
      goto err;
 
2658
    }
 
2659
 
 
2660
    sort_param[i].key_length=share->rec_reflength;
 
2661
    for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END;
 
2662
         keyseg++)
 
2663
    {
 
2664
      sort_param[i].key_length+=keyseg->length;
 
2665
      if (keyseg->flag & HA_SPACE_PACK)
 
2666
        sort_param[i].key_length+=get_pack_length(keyseg->length);
 
2667
      if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
 
2668
        sort_param[i].key_length+=2 + test(keyseg->length >= 127);
 
2669
      if (keyseg->flag & HA_NULL_PART)
 
2670
        sort_param[i].key_length++;
 
2671
    }
 
2672
    total_key_length+=sort_param[i].key_length;
 
2673
  }
 
2674
  sort_info.total_keys=i;
 
2675
  sort_param[0].master= 1;
 
2676
  sort_param[0].fix_datafile= (my_bool)(! rep_quick);
 
2677
  sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
 
2678
 
 
2679
  sort_info.got_error=0;
 
2680
  pthread_mutex_lock(&sort_info.mutex);
 
2681
 
 
2682
  /*
 
2683
    Initialize the I/O cache share for use with the read caches and, in
 
2684
    case of non-quick repair, the write cache. When all threads join on
 
2685
    the cache lock, the writer copies the write cache contents to the
 
2686
    read caches.
 
2687
  */
 
2688
  if (i > 1)
 
2689
  {
 
2690
    if (rep_quick)
 
2691
      init_io_cache_share(&param->read_cache, &io_share, NULL, i);
 
2692
    else
 
2693
      init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i);
 
2694
  }
 
2695
  else
 
2696
    io_share.total_threads= 0; /* share not used */
 
2697
 
 
2698
  (void) pthread_attr_init(&thr_attr);
 
2699
  (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
 
2700
 
 
2701
  for (i=0 ; i < sort_info.total_keys ; i++)
 
2702
  {
 
2703
    /*
 
2704
      Copy the properly initialized IO_CACHE structure so that every
 
2705
      thread has its own copy. In quick mode param->read_cache is shared
 
2706
      for use by all threads. In non-quick mode all threads but the
 
2707
      first copy the shared new_data_cache, which is synchronized to the
 
2708
      write cache of the first thread. The first thread copies
 
2709
      param->read_cache, which is not shared.
 
2710
    */
 
2711
    sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache :
 
2712
                               new_data_cache);
 
2713
 
 
2714
    /*
 
2715
      two approaches: the same amount of memory for each thread
 
2716
      or the memory for the same number of keys for each thread...
 
2717
      In the second one all the threads will fill their sort_buffers
 
2718
      (and call write_keys) at the same time, putting more stress on i/o.
 
2719
    */
 
2720
    sort_param[i].sortbuff_size=
 
2721
#ifndef USING_SECOND_APPROACH
 
2722
      param->sort_buffer_length/sort_info.total_keys;
 
2723
#else
 
2724
      param->sort_buffer_length*sort_param[i].key_length/total_key_length;
 
2725
#endif
 
2726
    if (pthread_create(&sort_param[i].thr, &thr_attr,
 
2727
                       thr_find_all_keys,
 
2728
                       (void *) (sort_param+i)))
 
2729
    {
 
2730
      mi_check_print_error(param,"Cannot start a repair thread");
 
2731
      /* Cleanup: Detach from the share. Avoid others to be blocked. */
 
2732
      if (io_share.total_threads)
 
2733
        remove_io_thread(&sort_param[i].read_cache);
 
2734
      sort_info.got_error=1;
 
2735
    }
 
2736
    else
 
2737
      sort_info.threads_running++;
 
2738
  }
 
2739
  (void) pthread_attr_destroy(&thr_attr);
 
2740
 
 
2741
  /* waiting for all threads to finish */
 
2742
  while (sort_info.threads_running)
 
2743
    pthread_cond_wait(&sort_info.cond, &sort_info.mutex);
 
2744
  pthread_mutex_unlock(&sort_info.mutex);
 
2745
 
 
2746
  if ((got_error= thr_write_keys(sort_param)))
 
2747
  {
 
2748
    param->retry_repair=1;
 
2749
    goto err;
 
2750
  }
 
2751
  got_error=1;                          /* Assume the following may go wrong */
 
2752
 
 
2753
  if (sort_param[0].fix_datafile)
 
2754
  {
 
2755
    /*
 
2756
      Append some nuls to the end of a memory mapped file. Destroy the
 
2757
      write cache. The master thread did already detach from the share
 
2758
      by remove_io_thread() in sort.c:thr_find_all_keys().
 
2759
    */
 
2760
    if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
 
2761
      goto err;
 
2762
    if (param->testflag & T_SAFE_REPAIR)
 
2763
    {
 
2764
      /* Don't repair if we loosed more than one row */
 
2765
      if (info->state->records+1 < start_records)
 
2766
      {
 
2767
        info->state->records=start_records;
 
2768
        goto err;
 
2769
      }
 
2770
    }
 
2771
    share->state.state.data_file_length= info->state->data_file_length=
 
2772
      sort_param->filepos;
 
2773
    /* Only whole records */
 
2774
    share->state.version=(ulong) time((time_t*) 0);
 
2775
 
 
2776
    /*
 
2777
      Exchange the data file descriptor of the table, so that we use the
 
2778
      new file from now on.
 
2779
     */
 
2780
    my_close(info->dfile,MYF(0));
 
2781
    info->dfile=new_file;
 
2782
 
 
2783
    share->data_file_type=sort_info.new_data_file_type;
 
2784
    share->pack.header_length=(ulong) new_header_length;
 
2785
  }
 
2786
  else
 
2787
    info->state->data_file_length=sort_param->max_pos;
 
2788
 
 
2789
  if (rep_quick && del+sort_info.dupp != info->state->del)
 
2790
  {
 
2791
    mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
 
2792
    mi_check_print_error(param,"Run recovery again without -q");
 
2793
    param->retry_repair=1;
 
2794
    param->testflag|=T_RETRY_WITHOUT_QUICK;
 
2795
    goto err;
 
2796
  }
 
2797
 
 
2798
  if (rep_quick & T_FORCE_UNIQUENESS)
 
2799
  {
 
2800
    my_off_t skr=info->state->data_file_length+
 
2801
      (share->options & HA_OPTION_COMPRESS_RECORD ?
 
2802
       MEMMAP_EXTRA_MARGIN : 0);
 
2803
#ifdef USE_RELOC
 
2804
    if (share->data_file_type == STATIC_RECORD &&
 
2805
        skr < share->base.reloc*share->base.min_pack_length)
 
2806
      skr=share->base.reloc*share->base.min_pack_length;
 
2807
#endif
 
2808
    if (skr != sort_info.filelength && !info->s->base.raid_type)
 
2809
      if (ftruncate(info->dfile, skr))
 
2810
        mi_check_print_warning(param,
 
2811
                               "Can't change size of datafile,  error: %d",
 
2812
                               my_errno);
 
2813
  }
 
2814
  if (param->testflag & T_CALC_CHECKSUM)
 
2815
    info->state->checksum=param->glob_crc;
 
2816
 
 
2817
  if (ftruncate(share->kfile, info->state->key_file_length))
 
2818
    mi_check_print_warning(param,
 
2819
                           "Can't change size of indexfile, error: %d", my_errno);
 
2820
 
 
2821
  if (!(param->testflag & T_SILENT))
 
2822
  {
 
2823
    if (start_records != info->state->records)
 
2824
      printf("Data records: %s\n", llstr(info->state->records,llbuff));
 
2825
    if (sort_info.dupp)
 
2826
      mi_check_print_warning(param,
 
2827
                             "%s records have been removed",
 
2828
                             llstr(sort_info.dupp,llbuff));
 
2829
  }
 
2830
  got_error=0;
 
2831
 
 
2832
  if (&share->state.state != info->state)
 
2833
    memcpy(&share->state.state, info->state, sizeof(*info->state));
 
2834
 
 
2835
err:
 
2836
  got_error|= flush_blocks(param, share->key_cache, share->kfile);
 
2837
  /*
 
2838
    Destroy the write cache. The master thread did already detach from
 
2839
    the share by remove_io_thread() or it was not yet started (if the
 
2840
    error happend before creating the thread).
 
2841
  */
 
2842
  VOID(end_io_cache(&info->rec_cache));
 
2843
  /*
 
2844
    Destroy the new data cache in case of non-quick repair. All slave
 
2845
    threads did either detach from the share by remove_io_thread()
 
2846
    already or they were not yet started (if the error happend before
 
2847
    creating the threads).
 
2848
  */
 
2849
  if (!rep_quick)
 
2850
    VOID(end_io_cache(&new_data_cache));
 
2851
  if (!got_error)
 
2852
  {
 
2853
    /* Replace the actual file with the temporary file */
 
2854
    if (new_file >= 0)
 
2855
    {
 
2856
      my_close(new_file,MYF(0));
 
2857
      info->dfile=new_file= -1;
 
2858
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
 
2859
                            DATA_TMP_EXT, share->base.raid_chunks,
 
2860
                            (param->testflag & T_BACKUP_DATA ?
 
2861
                             MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
 
2862
          mi_open_datafile(info,share,-1))
 
2863
        got_error=1;
 
2864
    }
 
2865
  }
 
2866
  if (got_error)
 
2867
  {
 
2868
    if (! param->error_printed)
 
2869
      mi_check_print_error(param,"%d when fixing table",my_errno);
 
2870
    if (new_file >= 0)
 
2871
    {
 
2872
      VOID(my_close(new_file,MYF(0)));
 
2873
      VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks,
 
2874
                          MYF(MY_WME)));
 
2875
      if (info->dfile == new_file)
 
2876
        info->dfile= -1;
 
2877
    }
 
2878
    mi_mark_crashed_on_repair(info);
 
2879
  }
 
2880
  else if (key_map == share->state.key_map)
 
2881
    share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
 
2882
  share->state.changed|=STATE_NOT_SORTED_PAGES;
 
2883
 
 
2884
  pthread_cond_destroy (&sort_info.cond);
 
2885
  pthread_mutex_destroy(&sort_info.mutex);
 
2886
 
 
2887
  my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
 
2888
  my_free((uchar*) sort_param,MYF(MY_ALLOW_ZERO_PTR));
 
2889
  my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
 
2890
  VOID(end_io_cache(&param->read_cache));
 
2891
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
 
2892
  if (!got_error && (param->testflag & T_UNPACK))
 
2893
  {
 
2894
    share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
2338
2895
    share->pack.header_length=0;
2339
2896
  }
2340
2897
  return(got_error);
2342
2899
 
2343
2900
        /* Read next record and return next key */
2344
2901
 
2345
 
int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
 
2902
static int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
2346
2903
{
2347
2904
  int error;
2348
2905
  SORT_INFO *sort_info=sort_param->sort_info;
2359
2916
  }
2360
2917
  sort_param->real_key_length=
2361
2918
    (info->s->rec_reflength+
2362
 
     _mi_make_key(info, sort_param->key, (unsigned char*) key,
 
2919
     _mi_make_key(info, sort_param->key, (uchar*) key,
2363
2920
                  sort_param->record, sort_param->filepos));
2364
 
#ifdef HAVE_VALGRIND
2365
 
  memset((unsigned char *)key+sort_param->real_key_length, 0,
 
2921
#ifdef HAVE_purify
 
2922
  memset(key+sort_param->real_key_length, 0,
2366
2923
         (sort_param->key_length-sort_param->real_key_length));
2367
2924
#endif
2368
2925
  return(sort_write_record(sort_param));
2400
2957
    > 0         error
2401
2958
*/
2402
2959
 
2403
 
int sort_get_next_record(MI_SORT_PARAM *sort_param)
 
2960
static int sort_get_next_record(MI_SORT_PARAM *sort_param)
2404
2961
{
2405
2962
  int searching;
2406
2963
  int parallel_flag;
2407
 
  uint32_t found_record,b_type,left_length;
 
2964
  uint found_record,b_type,left_length;
2408
2965
  my_off_t pos;
2409
 
  unsigned char *to= NULL;
 
2966
  uchar *to= NULL;
2410
2967
  MI_BLOCK_INFO block_info;
2411
2968
  SORT_INFO *sort_info=sort_param->sort_info;
2412
2969
  MI_CHECK *param=sort_info->param;
2482
3039
                     llstr(param->search_after_block,llbuff),
2483
3040
                     llstr(sort_param->start_recpos,llbuff2));
2484
3041
        if (_mi_read_cache(&sort_param->read_cache,
2485
 
                           (unsigned char*) block_info.header,pos,
 
3042
                           (uchar*) block_info.header,pos,
2486
3043
                           MI_BLOCK_INFO_HEADER_LENGTH,
2487
3044
                           (! found_record ? READING_NEXT : 0) |
2488
3045
                           parallel_flag | READING_HEADER))
2509
3066
             (block_info.rec_len < (uint) share->base.min_pack_length ||
2510
3067
              block_info.rec_len > (uint) share->base.max_pack_length)))
2511
3068
        {
2512
 
          uint32_t i;
 
3069
          uint i;
2513
3070
          if (param->testflag & T_VERBOSE || searching == 0)
2514
3071
            mi_check_print_info(param,
2515
3072
                                "Wrong bytesec: %3d-%3d-%3d at %10s; Skipped",
2532
3089
        }
2533
3090
        if (b_type & BLOCK_DELETED)
2534
3091
        {
2535
 
          bool error=0;
 
3092
          my_bool error=0;
2536
3093
          if (block_info.block_len+ (uint) (block_info.filepos-pos) <
2537
3094
              share->base.min_block_length)
2538
3095
          {
2668
3225
          streched over the end of the previous buffer contents.
2669
3226
        */
2670
3227
        {
2671
 
          uint32_t header_len= (uint) (block_info.filepos - pos);
2672
 
          uint32_t prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len);
 
3228
          uint header_len= (uint) (block_info.filepos - pos);
 
3229
          uint prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len);
2673
3230
 
2674
3231
          if (prefetch_len > block_info.data_len)
2675
3232
            prefetch_len= block_info.data_len;
2690
3247
        {
2691
3248
          mi_check_print_info(param,
2692
3249
                              "Read error for block at: %s (error: %d); Skipped",
2693
 
                              llstr(block_info.filepos,llbuff),errno);
 
3250
                              llstr(block_info.filepos,llbuff),my_errno);
2694
3251
          goto try_next;
2695
3252
        }
2696
3253
        left_length-=block_info.data_len;
2744
3301
      searching=1;
2745
3302
    }
2746
3303
  case COMPRESSED_RECORD:
 
3304
    for (searching=0 ;; searching=1, sort_param->pos++)
 
3305
    {
 
3306
      if (_mi_read_cache(&sort_param->read_cache,(uchar*) block_info.header,
 
3307
                         sort_param->pos,
 
3308
                         share->pack.ref_length,READING_NEXT))
 
3309
        return(-1);
 
3310
      if (searching && ! sort_param->fix_datafile)
 
3311
      {
 
3312
        param->error_printed=1;
 
3313
        param->retry_repair=1;
 
3314
        param->testflag|=T_RETRY_WITHOUT_QUICK;
 
3315
        return(1);              /* Something wrong with data */
 
3316
      }
 
3317
      sort_param->start_recpos=sort_param->pos;
 
3318
      if (_mi_pack_get_block_info(info, &sort_param->bit_buff, &block_info,
 
3319
                                  &sort_param->rec_buff, -1, sort_param->pos))
 
3320
        return(-1);
 
3321
      if (!block_info.rec_len &&
 
3322
          sort_param->pos + MEMMAP_EXTRA_MARGIN ==
 
3323
          sort_param->read_cache.end_of_file)
 
3324
        return(-1);
 
3325
      if (block_info.rec_len < (uint) share->min_pack_length ||
 
3326
          block_info.rec_len > (uint) share->max_pack_length)
 
3327
      {
 
3328
        if (! searching)
 
3329
          mi_check_print_info(param,"Found block with wrong recordlength: %d at %s\n",
 
3330
                              block_info.rec_len,
 
3331
                              llstr(sort_param->pos,llbuff));
 
3332
        continue;
 
3333
      }
 
3334
      if (_mi_read_cache(&sort_param->read_cache,(uchar*) sort_param->rec_buff,
 
3335
                         block_info.filepos, block_info.rec_len,
 
3336
                         READING_NEXT))
 
3337
      {
 
3338
        if (! searching)
 
3339
          mi_check_print_info(param,"Couldn't read whole record from %s",
 
3340
                              llstr(sort_param->pos,llbuff));
 
3341
        continue;
 
3342
      }
 
3343
      if (_mi_pack_rec_unpack(info, &sort_param->bit_buff, sort_param->record,
 
3344
                              sort_param->rec_buff, block_info.rec_len))
 
3345
      {
 
3346
        if (! searching)
 
3347
          mi_check_print_info(param,"Found wrong record at %s",
 
3348
                              llstr(sort_param->pos,llbuff));
 
3349
        continue;
 
3350
      }
 
3351
      if (!sort_param->fix_datafile)
 
3352
      {
 
3353
        sort_param->filepos=sort_param->pos;
 
3354
        if (sort_param->master)
 
3355
          share->state.split++;
 
3356
      }
 
3357
      sort_param->max_pos=(sort_param->pos=block_info.filepos+
 
3358
                         block_info.rec_len);
 
3359
      info->packed_length=block_info.rec_len;
 
3360
      if (sort_param->calc_checksum)
 
3361
        param->glob_crc+= (info->checksum=
 
3362
                           mi_checksum(info, sort_param->record));
 
3363
      return(0);
 
3364
    }
2747
3365
  case BLOCK_RECORD:
2748
3366
    assert(0);                                  /* Impossible */
2749
3367
  }
2769
3387
int sort_write_record(MI_SORT_PARAM *sort_param)
2770
3388
{
2771
3389
  int flag;
 
3390
  uint length;
2772
3391
  ulong block_length,reclength;
2773
 
  unsigned char *from;
 
3392
  uchar *from;
 
3393
  uchar block_buff[8];
2774
3394
  SORT_INFO *sort_info=sort_param->sort_info;
2775
3395
  MI_CHECK *param=sort_info->param;
2776
3396
  MI_INFO *info=sort_info->info;
2783
3403
      if (my_b_write(&info->rec_cache,sort_param->record,
2784
3404
                     share->base.pack_reclength))
2785
3405
      {
2786
 
        mi_check_print_error(param,"%d when writing to datafile",errno);
 
3406
        mi_check_print_error(param,"%d when writing to datafile",my_errno);
2787
3407
        return(1);
2788
3408
      }
2789
3409
      sort_param->filepos+=share->base.pack_reclength;
2802
3422
          MI_DYN_DELETE_BLOCK_HEADER;
2803
3423
        if (sort_info->buff_length < reclength)
2804
3424
        {
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
 
          }
 
3425
          if (!(sort_info->buff=my_realloc(sort_info->buff, (uint) reclength,
 
3426
                                           MYF(MY_FREE_ON_ERROR |
 
3427
                                               MY_ALLOW_ZERO_PTR))))
 
3428
            return(1);
 
3429
          sort_info->buff_length=reclength;
2818
3430
        }
2819
3431
        from= sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
2820
3432
      }
2837
3449
                                  sort_param->filepos+block_length,
2838
3450
                                  &from,&reclength,&flag))
2839
3451
        {
2840
 
          mi_check_print_error(param,"%d when writing to datafile",errno);
 
3452
          mi_check_print_error(param,"%d when writing to datafile",my_errno);
2841
3453
          return(1);
2842
3454
        }
2843
3455
        sort_param->filepos+=block_length;
2846
3458
      /* sort_info->param->glob_crc+=info->checksum; */
2847
3459
      break;
2848
3460
    case COMPRESSED_RECORD:
 
3461
      reclength=info->packed_length;
 
3462
      length= save_pack_length((uint) share->pack.version, block_buff,
 
3463
                               reclength);
 
3464
      if (info->s->base.blobs)
 
3465
        length+= save_pack_length((uint) share->pack.version,
 
3466
                                  block_buff + length, info->blob_length);
 
3467
      if (my_b_write(&info->rec_cache,block_buff,length) ||
 
3468
          my_b_write(&info->rec_cache,(uchar*) sort_param->rec_buff,reclength))
 
3469
      {
 
3470
        mi_check_print_error(param,"%d when writing to datafile",my_errno);
 
3471
        return(1);
 
3472
      }
 
3473
      /* sort_info->param->glob_crc+=info->checksum; */
 
3474
      sort_param->filepos+=reclength+length;
 
3475
      info->s->state.split++;
 
3476
      break;
2849
3477
    case BLOCK_RECORD:
2850
3478
      assert(0);                                  /* Impossible */
2851
3479
    }
2858
3486
    {
2859
3487
      char llbuff[22];
2860
3488
      printf("%s\r", llstr(info->state->records,llbuff));
2861
 
      fflush(stdout);
 
3489
      VOID(fflush(stdout));
2862
3490
    }
2863
3491
  }
2864
3492
  return(0);
2867
3495
 
2868
3496
        /* Compare two keys from _create_index_by_sort */
2869
3497
 
2870
 
int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a, const void *b)
 
3498
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,
 
3499
                        const void *b)
2871
3500
{
2872
 
  uint32_t not_used[2];
2873
 
  return (ha_key_cmp(sort_param->seg, *((unsigned char* const *) a), *((unsigned char* const *) b),
 
3501
  uint not_used[2];
 
3502
  return (ha_key_cmp(sort_param->seg, *((uchar**) a), *((uchar**) b),
2874
3503
                     USE_WHOLE_KEY, SEARCH_SAME, not_used));
2875
3504
} /* sort_key_cmp */
2876
3505
 
2877
3506
 
2878
 
int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
 
3507
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
2879
3508
{
2880
 
  uint32_t diff_pos[2];
 
3509
  uint diff_pos[2];
2881
3510
  char llbuff[22],llbuff2[22];
2882
3511
  SORT_INFO *sort_info=sort_param->sort_info;
2883
3512
  MI_CHECK *param= sort_info->param;
2886
3515
  if (sort_info->key_block->inited)
2887
3516
  {
2888
3517
    cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
2889
 
                   (unsigned char*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
 
3518
                   (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
2890
3519
                   diff_pos);
2891
3520
    if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
2892
3521
      ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
2893
 
                 (unsigned char*) a, USE_WHOLE_KEY,
 
3522
                 (uchar*) a, USE_WHOLE_KEY, 
2894
3523
                 SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
2895
3524
    else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
2896
3525
    {
2897
3526
      diff_pos[0]= mi_collect_stats_nonulls_next(sort_param->seg,
2898
3527
                                                 sort_param->notnull,
2899
3528
                                                 sort_info->key_block->lastkey,
2900
 
                                                 (unsigned char*)a);
 
3529
                                                 (uchar*)a);
2901
3530
    }
2902
3531
    sort_param->unique[diff_pos[0]-1]++;
2903
3532
  }
2906
3535
    cmp= -1;
2907
3536
    if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
2908
3537
      mi_collect_stats_nonulls_first(sort_param->seg, sort_param->notnull,
2909
 
                                     (unsigned char*)a);
 
3538
                                     (uchar*)a);
2910
3539
  }
2911
3540
  if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0)
2912
3541
  {
2913
3542
    sort_info->dupp++;
2914
3543
    sort_info->info->lastpos=get_record_for_key(sort_info->info,
2915
3544
                                                sort_param->keyinfo,
2916
 
                                                (unsigned char*) a);
 
3545
                                                (uchar*) a);
2917
3546
    mi_check_print_warning(param,
2918
3547
                           "Duplicate key for record at %10s against record at %10s",
2919
3548
                           llstr(sort_info->info->lastpos,llbuff),
2926
3555
    return (sort_delete_record(sort_param));
2927
3556
  }
2928
3557
  return (sort_insert_key(sort_param,sort_info->key_block,
2929
 
                          (unsigned char*) a, HA_OFFSET_ERROR));
 
3558
                          (uchar*) a, HA_OFFSET_ERROR));
2930
3559
} /* sort_key_write */
2931
3560
 
2932
3561
 
2933
3562
        /* get pointer to record from a key */
2934
3563
 
2935
 
my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo,
2936
 
                            unsigned char *key) {
 
3564
static my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo,
 
3565
                                   uchar *key)
 
3566
{
2937
3567
  return _mi_dpos(info,0,key+_mi_keylength(keyinfo,key));
2938
3568
} /* get_record_for_key */
2939
3569
 
2940
3570
 
2941
3571
        /* Insert a key in sort-key-blocks */
2942
3572
 
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)
 
3573
static int sort_insert_key(MI_SORT_PARAM *sort_param,
 
3574
                           register SORT_KEY_BLOCKS *key_block, uchar *key,
 
3575
                           my_off_t prev_block)
2946
3576
{
2947
 
  uint32_t a_length,t_length,nod_flag;
 
3577
  uint a_length,t_length,nod_flag;
2948
3578
  my_off_t filepos,key_file_length;
2949
 
  unsigned char *anc_buff,*lastkey;
 
3579
  uchar *anc_buff,*lastkey;
2950
3580
  MI_KEY_PARAM s_temp;
2951
3581
  MI_INFO *info;
2952
3582
  MI_KEYDEF *keyinfo=sort_param->keyinfo;
2979
3609
    _mi_kpointer(info,key_block->end_pos,prev_block);
2980
3610
 
2981
3611
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
2982
 
                                (unsigned char*) 0,lastkey,lastkey,key,
 
3612
                                (uchar*) 0,lastkey,lastkey,key,
2983
3613
                                 &s_temp);
2984
3614
  (*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp);
2985
3615
  a_length+=t_length;
2987
3617
  key_block->end_pos+=t_length;
2988
3618
  if (a_length <= keyinfo->block_length)
2989
3619
  {
2990
 
    _mi_move_key(keyinfo,key_block->lastkey,key);
 
3620
    VOID(_mi_move_key(keyinfo,key_block->lastkey,key));
2991
3621
    key_block->last_length=a_length-t_length;
2992
3622
    return(0);
2993
3623
  }
2994
3624
 
2995
3625
        /* Fill block with end-zero and write filled block */
2996
3626
  mi_putint(anc_buff,key_block->last_length,nod_flag);
2997
 
  memset(anc_buff+key_block->last_length, 0,
2998
 
         keyinfo->block_length - key_block->last_length);
 
3627
  memset((uchar*) anc_buff+key_block->last_length, 0,
 
3628
         keyinfo->block_length- key_block->last_length);
2999
3629
  key_file_length=info->state->key_file_length;
3000
3630
  if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
3001
3631
    return(1);
3006
3636
    if (_mi_write_keypage(info, keyinfo, filepos, DFLT_INIT_HITS, anc_buff))
3007
3637
      return(1);
3008
3638
  }
3009
 
  else if (my_pwrite(info->s->kfile,(unsigned char*) anc_buff,
 
3639
  else if (my_pwrite(info->s->kfile,(uchar*) anc_buff,
3010
3640
                     (uint) keyinfo->block_length,filepos, param->myf_rw))
3011
3641
    return(1);
3012
3642
 
3022
3652
 
3023
3653
        /* Delete record when we found a duplicated key */
3024
3654
 
3025
 
int sort_delete_record(MI_SORT_PARAM *sort_param)
 
3655
static int sort_delete_record(MI_SORT_PARAM *sort_param)
3026
3656
{
3027
 
  uint32_t i;
 
3657
  uint i;
3028
3658
  int old_file,error;
3029
 
  unsigned char *key;
 
3659
  uchar *key;
3030
3660
  SORT_INFO *sort_info=sort_param->sort_info;
3031
3661
  MI_CHECK *param=sort_info->param;
3032
3662
  MI_INFO *info=sort_info->info;
3059
3689
 
3060
3690
    for (i=0 ; i < sort_info->current_key ; i++)
3061
3691
    {
3062
 
      uint32_t key_length=_mi_make_key(info,i,key,sort_param->record,info->lastpos);
 
3692
      uint key_length=_mi_make_key(info,i,key,sort_param->record,info->lastpos);
3063
3693
      if (_mi_ck_delete(info,i,key,key_length))
3064
3694
      {
3065
3695
        mi_check_print_error(param,"Can't delete key %d from record to be removed",i+1);
3080
3710
 
3081
3711
int flush_pending_blocks(MI_SORT_PARAM *sort_param)
3082
3712
{
3083
 
  uint32_t nod_flag,length;
 
3713
  uint nod_flag,length;
3084
3714
  my_off_t filepos,key_file_length;
3085
3715
  SORT_KEY_BLOCKS *key_block;
3086
3716
  SORT_INFO *sort_info= sort_param->sort_info;
3097
3727
    if (nod_flag)
3098
3728
      _mi_kpointer(info,key_block->end_pos,filepos);
3099
3729
    key_file_length=info->state->key_file_length;
3100
 
    memset(key_block->buff+length, 0, keyinfo->block_length-length);
 
3730
    memset((uchar*) key_block->buff+length, 0, keyinfo->block_length-length);
3101
3731
    if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
3102
3732
      return(1);
3103
3733
 
3108
3738
                            DFLT_INIT_HITS, key_block->buff))
3109
3739
        return(1);
3110
3740
    }
3111
 
    else if (my_pwrite(info->s->kfile,(unsigned char*) key_block->buff,
 
3741
    else if (my_pwrite(info->s->kfile,(uchar*) key_block->buff,
3112
3742
                       (uint) keyinfo->block_length,filepos, myf_rw))
3113
3743
      return(1);
3114
3744
    nod_flag=1;
3119
3749
 
3120
3750
        /* alloc space and pointers for key_blocks */
3121
3751
 
3122
 
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint32_t blocks,
3123
 
                                         uint32_t buffer_length)
 
3752
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
 
3753
                                         uint buffer_length)
3124
3754
{
3125
 
  register uint32_t i;
 
3755
  register uint i;
3126
3756
  SORT_KEY_BLOCKS *block;
3127
3757
 
3128
 
  if (!(block=(SORT_KEY_BLOCKS*) malloc((sizeof(SORT_KEY_BLOCKS)+
3129
 
                                        buffer_length+IO_SIZE)*blocks)))
 
3758
  if (!(block=(SORT_KEY_BLOCKS*) my_malloc((sizeof(SORT_KEY_BLOCKS)+
 
3759
                                            buffer_length+IO_SIZE)*blocks,
 
3760
                                           MYF(0))))
3130
3761
  {
3131
3762
    mi_check_print_error(param,"Not enough memory for sort-key-blocks");
3132
3763
    return(0);
3134
3765
  for (i=0 ; i < blocks ; i++)
3135
3766
  {
3136
3767
    block[i].inited=0;
3137
 
    block[i].buff=(unsigned char*) (block+blocks)+(buffer_length+IO_SIZE)*i;
 
3768
    block[i].buff=(uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
3138
3769
  }
3139
3770
  return(block);
3140
3771
} /* alloc_key_blocks */
3146
3777
{
3147
3778
  if (info->s->options & HA_OPTION_COMPRESS_RECORD)
3148
3779
    return 0;
3149
 
  return (my_off_t)(lseek(info->s->kfile, 0L, SEEK_END) / 10 * 9) >
 
3780
  return my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(MY_THREADSAFE)) / 10 * 9 >
3150
3781
         (my_off_t) info->s->base.max_key_file_length ||
3151
 
         (my_off_t)(lseek(info->dfile, 0L, SEEK_END) / 10 * 9) >
 
3782
         my_seek(info->dfile, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 >
3152
3783
         (my_off_t) info->s->base.max_data_file_length;
3153
3784
}
3154
3785
 
 
3786
        /* Recreate table with bigger more alloced record-data */
 
3787
 
 
3788
int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
 
3789
{
 
3790
  int error;
 
3791
  MI_INFO info;
 
3792
  MYISAM_SHARE share;
 
3793
  MI_KEYDEF *keyinfo,*key,*key_end;
 
3794
  HA_KEYSEG *keysegs,*keyseg;
 
3795
  MI_COLUMNDEF *recdef,*rec,*end;
 
3796
  MI_UNIQUEDEF *uniquedef,*u_ptr,*u_end;
 
3797
  MI_STATUS_INFO status_info;
 
3798
  uint unpack,key_parts;
 
3799
  ha_rows max_records;
 
3800
  uint64_t file_length,tmp_length;
 
3801
  MI_CREATE_INFO create_info;
 
3802
 
 
3803
  error=1;                                      /* Default error */
 
3804
  info= **org_info;
 
3805
  status_info= (*org_info)->state[0];
 
3806
  info.state= &status_info;
 
3807
  share= *(*org_info)->s;
 
3808
  unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
 
3809
    (param->testflag & T_UNPACK);
 
3810
  if (!(keyinfo=(MI_KEYDEF*) my_alloca(sizeof(MI_KEYDEF)*share.base.keys)))
 
3811
    return(0);
 
3812
  memcpy((uchar*) keyinfo,(uchar*) share.keyinfo,
 
3813
         (size_t) (sizeof(MI_KEYDEF)*share.base.keys));
 
3814
 
 
3815
  key_parts= share.base.all_key_parts;
 
3816
  if (!(keysegs=(HA_KEYSEG*) my_alloca(sizeof(HA_KEYSEG)*
 
3817
                                       (key_parts+share.base.keys))))
 
3818
  {
 
3819
    my_afree((uchar*) keyinfo);
 
3820
    return(1);
 
3821
  }
 
3822
  if (!(recdef=(MI_COLUMNDEF*)
 
3823
        my_alloca(sizeof(MI_COLUMNDEF)*(share.base.fields+1))))
 
3824
  {
 
3825
    my_afree((uchar*) keyinfo);
 
3826
    my_afree((uchar*) keysegs);
 
3827
    return(1);
 
3828
  }
 
3829
  if (!(uniquedef=(MI_UNIQUEDEF*)
 
3830
        my_alloca(sizeof(MI_UNIQUEDEF)*(share.state.header.uniques+1))))
 
3831
  {
 
3832
    my_afree((uchar*) recdef);
 
3833
    my_afree((uchar*) keyinfo);
 
3834
    my_afree((uchar*) keysegs);
 
3835
    return(1);
 
3836
  }
 
3837
 
 
3838
  /* Copy the column definitions */
 
3839
  memcpy((uchar*) recdef,(uchar*) share.rec,
 
3840
         (size_t) (sizeof(MI_COLUMNDEF)*(share.base.fields+1)));
 
3841
  for (rec=recdef,end=recdef+share.base.fields; rec != end ; rec++)
 
3842
  {
 
3843
    if (unpack && !(share.options & HA_OPTION_PACK_RECORD) &&
 
3844
        rec->type != FIELD_BLOB &&
 
3845
        rec->type != FIELD_VARCHAR &&
 
3846
        rec->type != FIELD_CHECK)
 
3847
      rec->type=(int) FIELD_NORMAL;
 
3848
  }
 
3849
 
 
3850
  /* Change the new key to point at the saved key segments */
 
3851
  memcpy((uchar*) keysegs,(uchar*) share.keyparts,
 
3852
         (size_t) (sizeof(HA_KEYSEG)*(key_parts+share.base.keys+
 
3853
                                      share.state.header.uniques)));
 
3854
  keyseg=keysegs;
 
3855
  for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
 
3856
  {
 
3857
    key->seg=keyseg;
 
3858
    for (; keyseg->type ; keyseg++)
 
3859
    {
 
3860
      if (param->language)
 
3861
        keyseg->language=param->language;       /* change language */
 
3862
    }
 
3863
    keyseg++;                                   /* Skip end pointer */
 
3864
  }
 
3865
 
 
3866
  /* Copy the unique definitions and change them to point at the new key
 
3867
     segments*/
 
3868
  memcpy((uchar*) uniquedef,(uchar*) share.uniqueinfo,
 
3869
         (size_t) (sizeof(MI_UNIQUEDEF)*(share.state.header.uniques)));
 
3870
  for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques;
 
3871
       u_ptr != u_end ; u_ptr++)
 
3872
  {
 
3873
    u_ptr->seg=keyseg;
 
3874
    keyseg+=u_ptr->keysegs+1;
 
3875
  }
 
3876
  if (share.options & HA_OPTION_COMPRESS_RECORD)
 
3877
    share.base.records=max_records=info.state->records;
 
3878
  else if (share.base.min_pack_length)
 
3879
    max_records=(ha_rows) (my_seek(info.dfile,0L,MY_SEEK_END,MYF(0)) /
 
3880
                           (ulong) share.base.min_pack_length);
 
3881
  else
 
3882
    max_records=0;
 
3883
  unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
 
3884
    (param->testflag & T_UNPACK);
 
3885
  share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
 
3886
 
 
3887
  file_length=(uint64_t) my_seek(info.dfile,0L,MY_SEEK_END,MYF(0));
 
3888
  tmp_length= file_length+file_length/10;
 
3889
  set_if_bigger(file_length,param->max_data_file_length);
 
3890
  set_if_bigger(file_length,tmp_length);
 
3891
  set_if_bigger(file_length,(uint64_t) share.base.max_data_file_length);
 
3892
 
 
3893
  VOID(mi_close(*org_info));
 
3894
  memset((char*) &create_info, 0, sizeof(create_info));
 
3895
  create_info.max_rows=max(max_records,share.base.records);
 
3896
  create_info.reloc_rows=share.base.reloc;
 
3897
  create_info.old_options=(share.options |
 
3898
                           (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));
 
3899
 
 
3900
  create_info.data_file_length=file_length;
 
3901
  create_info.auto_increment=share.state.auto_increment;
 
3902
  create_info.language = (param->language ? param->language :
 
3903
                          share.state.header.language);
 
3904
  create_info.key_file_length=  status_info.key_file_length;
 
3905
  /*
 
3906
    Allow for creating an auto_increment key. This has an effect only if
 
3907
    an auto_increment key exists in the original table.
 
3908
  */
 
3909
  create_info.with_auto_increment= true;
 
3910
  /* We don't have to handle symlinks here because we are using
 
3911
     HA_DONT_TOUCH_DATA */
 
3912
  if (mi_create(filename,
 
3913
                share.base.keys - share.state.header.uniques,
 
3914
                keyinfo, share.base.fields, recdef,
 
3915
                share.state.header.uniques, uniquedef,
 
3916
                &create_info,
 
3917
                HA_DONT_TOUCH_DATA))
 
3918
  {
 
3919
    mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno);
 
3920
    goto end;
 
3921
  }
 
3922
  *org_info=mi_open(filename,O_RDWR,
 
3923
                    (param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
 
3924
                    (param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
 
3925
                    HA_OPEN_ABORT_IF_LOCKED);
 
3926
  if (!*org_info)
 
3927
  {
 
3928
    mi_check_print_error(param,"Got error %d when trying to open re-created indexfile",
 
3929
                my_errno);
 
3930
    goto end;
 
3931
  }
 
3932
  /* We are modifing */
 
3933
  (*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
 
3934
  VOID(_mi_readinfo(*org_info,F_WRLCK,0));
 
3935
  (*org_info)->state->records=info.state->records;
 
3936
  if (share.state.create_time)
 
3937
    (*org_info)->s->state.create_time=share.state.create_time;
 
3938
  (*org_info)->s->state.unique=(*org_info)->this_unique=
 
3939
    share.state.unique;
 
3940
  (*org_info)->state->checksum=info.state->checksum;
 
3941
  (*org_info)->state->del=info.state->del;
 
3942
  (*org_info)->s->state.dellink=share.state.dellink;
 
3943
  (*org_info)->state->empty=info.state->empty;
 
3944
  (*org_info)->state->data_file_length=info.state->data_file_length;
 
3945
  if (update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
 
3946
                        UPDATE_OPEN_COUNT))
 
3947
    goto end;
 
3948
  error=0;
 
3949
end:
 
3950
  my_afree((uchar*) uniquedef);
 
3951
  my_afree((uchar*) keyinfo);
 
3952
  my_afree((uchar*) recdef);
 
3953
  my_afree((uchar*) keysegs);
 
3954
  return(error);
 
3955
}
 
3956
 
3155
3957
 
3156
3958
        /* write suffix to data file if neaded */
3157
3959
 
3158
 
int write_data_suffix(SORT_INFO *sort_info, bool fix_datafile)
 
3960
int write_data_suffix(SORT_INFO *sort_info, my_bool fix_datafile)
3159
3961
{
3160
3962
  MI_INFO *info=sort_info->info;
3161
3963
 
3162
3964
  if (info->s->options & HA_OPTION_COMPRESS_RECORD && fix_datafile)
3163
3965
  {
3164
 
    unsigned char buff[MEMMAP_EXTRA_MARGIN];
 
3966
    uchar buff[MEMMAP_EXTRA_MARGIN];
3165
3967
    memset(buff, 0, sizeof(buff));
3166
3968
    if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
3167
3969
    {
3168
3970
      mi_check_print_error(sort_info->param,
3169
 
                           "%d when writing to datafile",errno);
 
3971
                           "%d when writing to datafile",my_errno);
3170
3972
      return 1;
3171
3973
    }
3172
3974
    sort_info->param->read_cache.end_of_file+=sizeof(buff);
3176
3978
 
3177
3979
        /* Update state and myisamchk_time of indexfile */
3178
3980
 
3179
 
int update_state_info(MI_CHECK *param, MI_INFO *info,uint32_t update)
 
3981
int update_state_info(MI_CHECK *param, MI_INFO *info,uint update)
3180
3982
{
3181
3983
  MYISAM_SHARE *share=info->s;
3182
3984
 
3187
3989
  }
3188
3990
  if (update & UPDATE_STAT)
3189
3991
  {
3190
 
    uint32_t i, key_parts= mi_uint2korr(share->state.header.key_parts);
 
3992
    uint i, key_parts= mi_uint2korr(share->state.header.key_parts);
3191
3993
    share->state.rec_per_key_rows=info->state->records;
3192
3994
    share->state.changed&= ~STATE_NOT_ANALYZED;
3193
3995
    if (info->state->records)
3221
4023
  }
3222
4024
  {                                             /* Force update of status */
3223
4025
    int error;
3224
 
    uint32_t r_locks=share->r_locks,w_locks=share->w_locks;
 
4026
    uint r_locks=share->r_locks,w_locks=share->w_locks;
3225
4027
    share->r_locks= share->w_locks= share->tot_locks= 0;
3226
4028
    error=_mi_writeinfo(info,WRITEINFO_NO_UNLOCK);
3227
4029
    share->r_locks=r_locks;
3231
4033
      return 0;
3232
4034
  }
3233
4035
err:
3234
 
  mi_check_print_error(param,"%d when updating keyfile",errno);
 
4036
  mi_check_print_error(param,"%d when updating keyfile",my_errno);
3235
4037
  return 1;
3236
4038
}
3237
4039
 
3249
4051
        */
3250
4052
 
3251
4053
void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
3252
 
                               bool repair_only)
 
4054
                               my_bool repair_only)
3253
4055
{
3254
 
  unsigned char *record= 0;
 
4056
  uchar *record= 0;
3255
4057
 
3256
4058
  if (!info->s->base.auto_key ||
3257
4059
      ! mi_is_key_active(info->s->state.key_map, info->s->base.auto_key - 1))
3266
4068
      !(param->testflag & T_REP))
3267
4069
    printf("Updating MyISAM file: %s\n", param->isam_file_name);
3268
4070
  /*
3269
 
    We have to use an allocated buffer instead of info->rec_buff as
 
4071
    We have to use an allocated buffer instead of info->rec_buff as 
3270
4072
    _mi_put_key_in_record() may use info->rec_buff
3271
4073
  */
3272
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
 
4074
  if (!mi_alloc_rec_buff(info, -1, &record))
3273
4075
  {
3274
4076
    mi_check_print_error(param,"Not enough memory for extra record");
3275
4077
    return;
3278
4080
  mi_extra(info,HA_EXTRA_KEYREAD,0);
3279
4081
  if (mi_rlast(info, record, info->s->base.auto_key-1))
3280
4082
  {
3281
 
    if (errno != HA_ERR_END_OF_FILE)
 
4083
    if (my_errno != HA_ERR_END_OF_FILE)
3282
4084
    {
3283
4085
      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);
 
4086
      my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
 
4087
      mi_check_print_error(param,"%d when reading last record",my_errno);
3286
4088
      return;
3287
4089
    }
3288
4090
    if (!repair_only)
3296
4098
      set_if_bigger(info->s->state.auto_increment, param->auto_increment_value);
3297
4099
  }
3298
4100
  mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
3299
 
  free(mi_get_rec_buff_ptr(info, record));
 
4101
  my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
3300
4102
  update_state_info(param, info, UPDATE_AUTO_INC);
3301
4103
  return;
3302
4104
}
3314
4116
      records               Number of records in the table
3315
4117
 
3316
4118
  DESCRIPTION
3317
 
    This function is called produce index statistics values from unique and
 
4119
    This function is called produce index statistics values from unique and 
3318
4120
    notnull_tuples arrays after these arrays were produced with sequential
3319
4121
    index scan (the scan is done in two places: chk_index() and
3320
4122
    sort_key_write()).
3328
4130
 
3329
4131
    For MI_STATS_METHOD_IGNORE_NULLS method, notnull_tuples is an array too:
3330
4132
      notnull_tuples[0]= (#of {keypart1} tuples such that keypart1 is not NULL)
3331
 
      notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all
 
4133
      notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all 
3332
4134
                          keypart{i} are not NULL)
3333
4135
      ...
3334
4136
    For all other statistics collection methods notnull_tuples==NULL.
3335
4137
 
3336
4138
    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
 
 
 
4139
    rec_per_key_part[k] = 
 
4140
     = E(#records in the table such that keypart_1=c_1 AND ... AND 
 
4141
         keypart_k=c_k for arbitrary constants c_1 ... c_k) 
 
4142
     
3341
4143
     = {assuming that values have uniform distribution and index contains all
3342
4144
        tuples from the domain (or that {c_1, ..., c_k} tuple is choosen from
3343
4145
        index tuples}
3344
 
 
 
4146
     
3345
4147
     = #tuples-in-the-index / #distinct-tuples-in-the-index.
3346
 
 
3347
 
    The #tuples-in-the-index and #distinct-tuples-in-the-index have different
 
4148
    
 
4149
    The #tuples-in-the-index and #distinct-tuples-in-the-index have different 
3348
4150
    meaning depending on which statistics collection method is used:
3349
 
 
 
4151
    
3350
4152
    MI_STATS_METHOD_*  how are nulls compared?  which tuples are counted?
3351
4153
     NULLS_EQUAL            NULL == NULL           all tuples in table
3352
4154
     NULLS_NOT_EQUAL        NULL != NULL           all tuples in table
3359
4161
{
3360
4162
  uint64_t count=0,tmp, unique_tuples;
3361
4163
  uint64_t tuples= records;
3362
 
  uint32_t parts;
 
4164
  uint parts;
3363
4165
  for (parts=0 ; parts < keyinfo->keysegs  ; parts++)
3364
4166
  {
3365
4167
    count+=unique[parts];
3366
 
    unique_tuples= count + 1;
 
4168
    unique_tuples= count + 1;    
3367
4169
    if (notnull)
3368
4170
    {
3369
4171
      tuples= notnull[parts];
3370
 
      /*
3371
 
        #(unique_tuples not counting tuples with NULLs) =
3372
 
          #(unique_tuples counting tuples with NULLs as different) -
 
4172
      /* 
 
4173
        #(unique_tuples not counting tuples with NULLs) = 
 
4174
          #(unique_tuples counting tuples with NULLs as different) - 
3373
4175
          #(tuples with NULLs)
3374
4176
      */
3375
4177
      unique_tuples -= (records - notnull[parts]);
3376
4178
    }
3377
 
 
 
4179
    
3378
4180
    if (unique_tuples == 0)
3379
4181
      tmp= 1;
3380
4182
    else if (count == 0)
3382
4184
    else
3383
4185
      tmp= (tuples + unique_tuples/2) / unique_tuples;
3384
4186
 
3385
 
    /*
3386
 
      for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
 
4187
    /* 
 
4188
      for some weird keys (e.g. FULLTEXT) tmp can be <1 here. 
3387
4189
      let's ensure it is not
3388
4190
    */
3389
 
    if (tmp < 1)
3390
 
      tmp= 1;
 
4191
    set_if_bigger(tmp,1);
3391
4192
    if (tmp >= (uint64_t) ~(ulong) 0)
3392
4193
      tmp=(uint64_t) ~(ulong) 0;
3393
4194
 
3397
4198
}
3398
4199
 
3399
4200
 
3400
 
static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length)
 
4201
static ha_checksum mi_byte_checksum(const uchar *buf, uint length)
3401
4202
{
3402
4203
  ha_checksum crc;
3403
 
  const unsigned char *end=buf+length;
 
4204
  const uchar *end=buf+length;
3404
4205
  for (crc=0; buf != end; buf++)
3405
 
    crc=((crc << 1) + *((unsigned char*) buf)) +
 
4206
    crc=((crc << 1) + *((uchar*) buf)) +
3406
4207
      test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1)));
3407
4208
  return crc;
3408
4209
}
3409
4210
 
3410
 
static bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows)
 
4211
static my_bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows)
3411
4212
{
3412
 
  uint32_t key_maxlength=key->maxlength;
3413
 
  return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY) &&
 
4213
  uint key_maxlength=key->maxlength;
 
4214
  return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) &&
3414
4215
          ((uint64_t) rows * key_maxlength >
3415
 
           (uint64_t) MAX_FILE_SIZE));
 
4216
           (uint64_t) myisam_max_temp_length));
3416
4217
}
3417
4218
 
3418
4219
/*
3428
4229
{
3429
4230
  MYISAM_SHARE *share=info->s;
3430
4231
  MI_KEYDEF    *key=share->keyinfo;
3431
 
  uint32_t          i;
 
4232
  uint          i;
3432
4233
 
3433
4234
  assert(info->state->records == 0 &&
3434
4235
              (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES));
3435
4236
  for (i=0 ; i < share->base.keys ; i++,key++)
3436
4237
  {
3437
 
    if (!(key->flag & (HA_NOSAME | HA_AUTO_KEY)) &&
 
4238
    if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) &&
3438
4239
        ! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1)
3439
4240
    {
3440
4241
      mi_clear_key_active(share->state.key_map, i);
3450
4251
  even if the temporary file would be quite big!
3451
4252
*/
3452
4253
 
3453
 
bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
3454
 
                            uint64_t key_map, bool force)
 
4254
my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
 
4255
                            uint64_t key_map, my_bool force)
3455
4256
{
3456
4257
  MYISAM_SHARE *share=info->s;
3457
4258
  MI_KEYDEF *key=share->keyinfo;
3458
 
  uint32_t i;
 
4259
  uint i;
3459
4260
 
3460
4261
  /*
3461
4262
    mi_repair_by_sort only works if we have at least one key. If we don't
3486
4287
      sort_info->new_data_file_type = STATIC_RECORD;
3487
4288
 
3488
4289
    /* Set delete_function for sort_delete_record() */
3489
 
    memcpy(&tmp, share, sizeof(*share));
 
4290
    memcpy((char*) &tmp, share, sizeof(*share));
3490
4291
    tmp.options= ~HA_OPTION_COMPRESS_RECORD;
3491
4292
    mi_setup_functions(&tmp);
3492
4293
    share->delete_record=tmp.delete_record;