~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mi_check.c

Merging trunk changes from over weekend.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
  only. And it is sufficient to calculate the checksum once only.
41
41
*/
42
42
 
43
 
#include "ftdefs.h"
 
43
#include "myisamdef.h"
44
44
#include <m_ctype.h>
45
45
#include <stdarg.h>
46
46
#include <my_getopt.h>
50
50
#ifdef HAVE_SYS_MMAN_H
51
51
#include <sys/mman.h>
52
52
#endif
53
 
#include "rt_index.h"
54
53
 
55
54
#ifndef USE_RAID
56
55
#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
69
68
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
70
69
                          my_off_t pagepos, File new_file);
71
70
static int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
72
 
static int sort_ft_key_read(MI_SORT_PARAM *sort_param,void *key);
73
71
static int sort_get_next_record(MI_SORT_PARAM *sort_param);
74
72
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b);
75
 
static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a);
76
73
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a);
77
74
static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
78
75
                                uchar *key);
454
451
 
455
452
    if ((!(param->testflag & T_SILENT)))
456
453
      printf ("- check data record references index: %d\n",key+1);
457
 
    if (keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL))
458
 
      full_text_keys++;
459
454
    if (share->state.key_root[key] == HA_OFFSET_ERROR &&
460
455
        (info->state->records == 0 || keyinfo->flag & HA_FULLTEXT))
461
456
      goto do_stat;
743
738
  DBUG_ENTER("chk_index");
744
739
  DBUG_DUMP("buff",(uchar*) buff,mi_getint(buff));
745
740
 
746
 
  /* TODO: implement appropriate check for RTree keys */
747
 
  if (keyinfo->flag & HA_SPATIAL)
748
 
    DBUG_RETURN(0);
749
 
 
750
741
  if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
751
742
  {
752
743
    mi_check_print_error(param,"Not enough memory for keyblock");
836
827
    (*key_checksum)+= mi_byte_checksum((uchar*) key,
837
828
                                       key_length- info->s->rec_reflength);
838
829
    record= _mi_dpos(info,0,key+key_length);
839
 
    if (keyinfo->flag & HA_FULLTEXT) /* special handling for ft2 */
840
 
    {
841
 
      uint off;
842
 
      int  subkeys;
843
 
      get_key_full_length_rdonly(off, key);
844
 
      subkeys=ft_sintXkorr(key+off);
845
 
      if (subkeys < 0)
846
 
      {
847
 
        ha_rows tmp_keys=0;
848
 
        if (chk_index_down(param,info,&info->s->ft2_keyinfo,record,
849
 
                           temp_buff,&tmp_keys,key_checksum,1))
850
 
          goto err;
851
 
        if (tmp_keys + subkeys)
852
 
        {
853
 
          mi_check_print_error(param,
854
 
                               "Number of words in the 2nd level tree "
855
 
                               "does not match the number in the header. "
856
 
                               "Parent word in on the page %s, offset %u",
857
 
                               llstr(page,llbuff), (uint) (old_keypos-buff));
858
 
          goto err;
859
 
        }
860
 
        (*keys)+=tmp_keys-1;
861
 
        continue;
862
 
      }
863
 
      /* fall through */
864
 
    }
865
830
    if (record >= info->state->data_file_length)
866
831
    {
867
832
#ifndef DBUG_OFF
1239
1204
                 concurrent threads when running myisamchk
1240
1205
              */
1241
1206
              int search_result=
1242
 
#ifdef HAVE_RTREE_KEYS
1243
 
                (keyinfo->flag & HA_SPATIAL) ?
1244
 
                rtree_find_first(info, key, info->lastkey, key_length,
1245
 
                                 MBR_EQUAL | MBR_DATA) : 
1246
 
#endif
1247
1207
                _mi_search(info,keyinfo,info->lastkey,key_length,
1248
1208
                           SEARCH_SAME, info->s->state.key_root[key]);
1249
1209
              if (search_result)
1789
1749
  {
1790
1750
    if (mi_is_key_active(info->s->state.key_map, i))
1791
1751
    {
1792
 
      if (info->s->keyinfo[i].flag & HA_FULLTEXT )
1793
 
      {
1794
 
        if (_mi_ft_add(info, i, key, buff, filepos))
1795
 
          goto err;
1796
 
      }
1797
 
#ifdef HAVE_SPATIAL
1798
 
      else if (info->s->keyinfo[i].flag & HA_SPATIAL)
1799
 
      {
1800
 
        uint key_length=_mi_make_key(info,i,key,buff,filepos);
1801
 
        if (rtree_insert(info, i, key, key_length))
1802
 
          goto err;
1803
 
      }
1804
 
#endif /*HAVE_SPATIAL*/
1805
 
      else
1806
1752
      {
1807
1753
        uint key_length=_mi_make_key(info,i,key,buff,filepos);
1808
1754
        if (_mi_ck_write(info,i,key,key_length))
1820
1766
    {
1821
1767
      if (mi_is_key_active(info->s->state.key_map, i))
1822
1768
      {
1823
 
        if (info->s->keyinfo[i].flag & HA_FULLTEXT)
1824
 
        {
1825
 
          if (_mi_ft_del(info,i, key,buff,filepos))
1826
 
            break;
1827
 
        }
1828
 
        else
1829
1769
        {
1830
1770
          uint key_length=_mi_make_key(info,i,key,buff,filepos);
1831
1771
          if (_mi_ck_delete(info,i,key,key_length))
1936
1876
  /* cannot sort index files with R-tree indexes */
1937
1877
  for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
1938
1878
       key++,keyinfo++)
1939
 
    if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
1940
 
      DBUG_RETURN(0);
1941
1879
 
1942
1880
  if (!(param->testflag & T_SILENT))
1943
1881
    printf("- Sorting index for MyISAM-table '%s'\n",name);
2031
1969
  char llbuff[22];
2032
1970
  DBUG_ENTER("sort_one_index");
2033
1971
 
2034
 
  /* cannot walk over R-tree indices */
2035
 
  DBUG_ASSERT(keyinfo->key_alg != HA_KEY_ALG_RTREE);
2036
1972
  new_page_pos=param->new_file_pos;
2037
1973
  param->new_file_pos+=keyinfo->block_length;
2038
1974
 
2072
2008
          (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0)
2073
2009
        break;
2074
2010
      DBUG_ASSERT(keypos <= endpos);
2075
 
      if (keyinfo->flag & HA_FULLTEXT)
2076
 
      {
2077
 
        uint off;
2078
 
        int  subkeys;
2079
 
        get_key_full_length_rdonly(off, key);
2080
 
        subkeys=ft_sintXkorr(key+off);
2081
 
        if (subkeys < 0)
2082
 
        {
2083
 
          next_page= _mi_dpos(info,0,key+key_length);
2084
 
          _mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
2085
 
                       param->new_file_pos); /* Save new pos */
2086
 
          if (sort_one_index(param,info,&info->s->ft2_keyinfo,
2087
 
                             next_page,new_file))
2088
 
            goto err;
2089
 
        }
2090
 
      }
2091
2011
    }
2092
2012
  }
2093
2013
 
2318
2238
    my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
2319
2239
 
2320
2240
  sort_param.wordlist=NULL;
2321
 
  init_alloc_root(&sort_param.wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
2322
2241
 
2323
2242
  if (share->data_file_type == DYNAMIC_RECORD)
2324
2243
    length=max(share->base.min_pack_length+1,share->base.min_block_length);
2383
2302
    info->state->records=info->state->del=share->state.split=0;
2384
2303
    info->state->empty=0;
2385
2304
 
2386
 
    if (sort_param.keyinfo->flag & HA_FULLTEXT)
2387
 
    {
2388
 
      uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
2389
 
                                    sort_param.keyinfo->seg->charset->mbmaxlen;
2390
 
      sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
2391
 
      /*
2392
 
        fulltext indexes may have much more entries than the
2393
 
        number of rows in the table. We estimate the number here.
2394
 
 
2395
 
        Note, built-in parser is always nr. 0 - see ftparser_call_initializer()
2396
 
      */
2397
 
      if (sort_param.keyinfo->ftparser_nr == 0)
2398
 
      {
2399
 
        /*
2400
 
          for built-in parser the number of generated index entries
2401
 
          cannot be larger than the size of the data file divided
2402
 
          by the minimal word's length
2403
 
        */
2404
 
        sort_info.max_records=
2405
 
          (ha_rows) (sort_info.filelength/ft_min_word_len+1);
2406
 
      }
2407
 
      else
2408
 
      {
2409
 
        /*
2410
 
          for external plugin parser we cannot tell anything at all :(
2411
 
          so, we'll use all the sort memory and start from ~10 buffpeks.
2412
 
          (see _create_index_by_sort)
2413
 
        */
2414
 
        sort_info.max_records=
2415
 
          10*param->sort_buffer_length/sort_param.key_length;
2416
 
      }
2417
 
 
2418
 
      sort_param.key_read=sort_ft_key_read;
2419
 
      sort_param.key_write=sort_ft_key_write;
2420
 
    }
2421
 
    else
2422
2305
    {
2423
2306
      sort_param.key_read=sort_key_read;
2424
2307
      sort_param.key_write=sort_key_write;
2832
2715
    istep=1;
2833
2716
    if ((!(param->testflag & T_SILENT)))
2834
2717
      printf ("- Fixing index %d\n",key+1);
2835
 
    if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
2836
 
    {
2837
 
      sort_param[i].key_read=sort_ft_key_read;
2838
 
      sort_param[i].key_write=sort_ft_key_write;
2839
 
    }
2840
 
    else
2841
2718
    {
2842
2719
      sort_param[i].key_read=sort_key_read;
2843
2720
      sort_param[i].key_write=sort_key_write;
2874
2751
        sort_param[i].key_length++;
2875
2752
    }
2876
2753
    total_key_length+=sort_param[i].key_length;
2877
 
 
2878
 
    if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
2879
 
    {
2880
 
      uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
2881
 
                                    sort_param[i].keyinfo->seg->charset->mbmaxlen;
2882
 
      sort_param[i].key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
2883
 
      init_alloc_root(&sort_param[i].wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
2884
 
    }
2885
2754
  }
2886
2755
  sort_info.total_keys=i;
2887
2756
  sort_param[0].master= 1;
3142
3011
  DBUG_RETURN(sort_write_record(sort_param));
3143
3012
} /* sort_key_read */
3144
3013
 
3145
 
static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key)
3146
 
{
3147
 
  int error;
3148
 
  SORT_INFO *sort_info=sort_param->sort_info;
3149
 
  MI_INFO *info=sort_info->info;
3150
 
  FT_WORD *wptr=0;
3151
 
  DBUG_ENTER("sort_ft_key_read");
3152
 
 
3153
 
  if (!sort_param->wordlist)
3154
 
  {
3155
 
    for (;;)
3156
 
    {
3157
 
      free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
3158
 
      if ((error=sort_get_next_record(sort_param)))
3159
 
        DBUG_RETURN(error);
3160
 
      if (!(wptr=_mi_ft_parserecord(info,sort_param->key,sort_param->record,
3161
 
                                    &sort_param->wordroot)))
3162
 
        DBUG_RETURN(1);
3163
 
      if (wptr->pos)
3164
 
        break;
3165
 
      error=sort_write_record(sort_param);
3166
 
    }
3167
 
    sort_param->wordptr=sort_param->wordlist=wptr;
3168
 
  }
3169
 
  else
3170
 
  {
3171
 
    error=0;
3172
 
    wptr=(FT_WORD*)(sort_param->wordptr);
3173
 
  }
3174
 
 
3175
 
  sort_param->real_key_length=(info->s->rec_reflength+
3176
 
                               _ft_make_key(info, sort_param->key,
3177
 
                                            key, wptr++, sort_param->filepos));
3178
 
#ifdef HAVE_purify
3179
 
  if (sort_param->key_length > sort_param->real_key_length)
3180
 
    bzero(key+sort_param->real_key_length,
3181
 
          (sort_param->key_length-sort_param->real_key_length));
3182
 
#endif
3183
 
  if (!wptr->pos)
3184
 
  {
3185
 
    free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
3186
 
    sort_param->wordlist=0;
3187
 
    error=sort_write_record(sort_param);
3188
 
  }
3189
 
  else
3190
 
    sort_param->wordptr=(void*)wptr;
3191
 
 
3192
 
  DBUG_RETURN(error);
3193
 
} /* sort_ft_key_read */
3194
 
 
3195
3014
 
3196
3015
/*
3197
3016
  Read next record from file using parameters in sort_info.
3837
3656
                          (uchar*) a, HA_OFFSET_ERROR));
3838
3657
} /* sort_key_write */
3839
3658
 
3840
 
int sort_ft_buf_flush(MI_SORT_PARAM *sort_param)
3841
 
{
3842
 
  SORT_INFO *sort_info=sort_param->sort_info;
3843
 
  SORT_KEY_BLOCKS *key_block=sort_info->key_block;
3844
 
  MYISAM_SHARE *share=sort_info->info->s;
3845
 
  uint val_off, val_len;
3846
 
  int error;
3847
 
  SORT_FT_BUF *ft_buf=sort_info->ft_buf;
3848
 
  uchar *from, *to;
3849
 
 
3850
 
  val_len=share->ft2_keyinfo.keylength;
3851
 
  get_key_full_length_rdonly(val_off, ft_buf->lastkey);
3852
 
  to=ft_buf->lastkey+val_off;
3853
 
 
3854
 
  if (ft_buf->buf)
3855
 
  {
3856
 
    /* flushing first-level tree */
3857
 
    error=sort_insert_key(sort_param,key_block,ft_buf->lastkey,
3858
 
                          HA_OFFSET_ERROR);
3859
 
    for (from=to+val_len;
3860
 
         !error && from < ft_buf->buf;
3861
 
         from+= val_len)
3862
 
    {
3863
 
      memcpy(to, from, val_len);
3864
 
      error=sort_insert_key(sort_param,key_block,ft_buf->lastkey,
3865
 
                            HA_OFFSET_ERROR);
3866
 
    }
3867
 
    return error;
3868
 
  }
3869
 
  /* flushing second-level tree keyblocks */
3870
 
  error=flush_pending_blocks(sort_param);
3871
 
  /* updating lastkey with second-level tree info */
3872
 
  ft_intXstore(ft_buf->lastkey+val_off, -ft_buf->count);
3873
 
  _mi_dpointer(sort_info->info, ft_buf->lastkey+val_off+HA_FT_WLEN,
3874
 
      share->state.key_root[sort_param->key]);
3875
 
  /* restoring first level tree data in sort_info/sort_param */
3876
 
  sort_info->key_block=sort_info->key_block_end- sort_info->param->sort_key_blocks;
3877
 
  sort_param->keyinfo=share->keyinfo+sort_param->key;
3878
 
  share->state.key_root[sort_param->key]=HA_OFFSET_ERROR;
3879
 
  /* writing lastkey in first-level tree */
3880
 
  return error ? error :
3881
 
                 sort_insert_key(sort_param,sort_info->key_block,
3882
 
                                 ft_buf->lastkey,HA_OFFSET_ERROR);
3883
 
}
3884
 
 
3885
 
static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a)
3886
 
{
3887
 
  uint a_len, val_off, val_len, error;
3888
 
  uchar *p;
3889
 
  SORT_INFO *sort_info=sort_param->sort_info;
3890
 
  SORT_FT_BUF *ft_buf=sort_info->ft_buf;
3891
 
  SORT_KEY_BLOCKS *key_block=sort_info->key_block;
3892
 
 
3893
 
  val_len=HA_FT_WLEN+sort_info->info->s->base.rec_reflength;
3894
 
  get_key_full_length_rdonly(a_len, (uchar *)a);
3895
 
 
3896
 
  if (!ft_buf)
3897
 
  {
3898
 
    /*
3899
 
      use two-level tree only if key_reflength fits in rec_reflength place
3900
 
      and row format is NOT static - for _mi_dpointer not to garble offsets
3901
 
     */
3902
 
    if ((sort_info->info->s->base.key_reflength <=
3903
 
         sort_info->info->s->base.rec_reflength) &&
3904
 
        (sort_info->info->s->options &
3905
 
          (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
3906
 
      ft_buf=(SORT_FT_BUF *)my_malloc(sort_param->keyinfo->block_length +
3907
 
                                      sizeof(SORT_FT_BUF), MYF(MY_WME));
3908
 
 
3909
 
    if (!ft_buf)
3910
 
    {
3911
 
      sort_param->key_write=sort_key_write;
3912
 
      return sort_key_write(sort_param, a);
3913
 
    }
3914
 
    sort_info->ft_buf=ft_buf;
3915
 
    goto word_init_ft_buf; /* no need to duplicate the code */
3916
 
  }
3917
 
  get_key_full_length_rdonly(val_off, ft_buf->lastkey);
3918
 
 
3919
 
  if (ha_compare_text(sort_param->seg->charset,
3920
 
                      ((uchar *)a)+1,a_len-1,
3921
 
                      ft_buf->lastkey+1,val_off-1, 0, 0)==0)
3922
 
  {
3923
 
    if (!ft_buf->buf) /* store in second-level tree */
3924
 
    {
3925
 
      ft_buf->count++;
3926
 
      return sort_insert_key(sort_param,key_block,
3927
 
                             ((uchar *)a)+a_len, HA_OFFSET_ERROR);
3928
 
    }
3929
 
 
3930
 
    /* storing the key in the buffer. */
3931
 
    memcpy (ft_buf->buf, (char *)a+a_len, val_len);
3932
 
    ft_buf->buf+=val_len;
3933
 
    if (ft_buf->buf < ft_buf->end)
3934
 
      return 0;
3935
 
 
3936
 
    /* converting to two-level tree */
3937
 
    p=ft_buf->lastkey+val_off;
3938
 
 
3939
 
    while (key_block->inited)
3940
 
      key_block++;
3941
 
    sort_info->key_block=key_block;
3942
 
    sort_param->keyinfo=& sort_info->info->s->ft2_keyinfo;
3943
 
    ft_buf->count=(ft_buf->buf - p)/val_len;
3944
 
 
3945
 
    /* flushing buffer to second-level tree */
3946
 
    for (error=0; !error && p < ft_buf->buf; p+= val_len)
3947
 
      error=sort_insert_key(sort_param,key_block,p,HA_OFFSET_ERROR);
3948
 
    ft_buf->buf=0;
3949
 
    return error;
3950
 
  }
3951
 
 
3952
 
  /* flushing buffer */
3953
 
  if ((error=sort_ft_buf_flush(sort_param)))
3954
 
    return error;
3955
 
 
3956
 
word_init_ft_buf:
3957
 
  a_len+=val_len;
3958
 
  memcpy(ft_buf->lastkey, a, a_len);
3959
 
  ft_buf->buf=ft_buf->lastkey+a_len;
3960
 
  /*
3961
 
    32 is just a safety margin here
3962
 
    (at least max(val_len, sizeof(nod_flag)) should be there).
3963
 
    May be better performance could be achieved if we'd put
3964
 
      (sort_info->keyinfo->block_length-32)/XXX
3965
 
      instead.
3966
 
        TODO: benchmark the best value for XXX.
3967
 
  */
3968
 
  ft_buf->end=ft_buf->lastkey+ (sort_param->keyinfo->block_length-32);
3969
 
  return 0;
3970
 
} /* sort_ft_key_write */
3971
 
 
3972
3659
 
3973
3660
        /* get pointer to record from a key */
3974
3661
 
4630
4317
static my_bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows)
4631
4318
{
4632
4319
  uint key_maxlength=key->maxlength;
4633
 
  if (key->flag & HA_FULLTEXT)
4634
 
  {
4635
 
    uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
4636
 
                                  key->seg->charset->mbmaxlen;
4637
 
    key_maxlength+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
4638
 
  }
4639
 
  return (key->flag & HA_SPATIAL) ||
4640
 
          (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) &&
 
4320
  return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) &&
4641
4321
          ((ulonglong) rows * key_maxlength >
4642
4322
           (ulonglong) myisam_max_temp_length));
4643
4323
}