~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mi_check.cc

  • Committer: Brian Aker
  • Date: 2009-10-02 21:34:26 UTC
  • mfrom: (1134.1.4 bug426504)
  • Revision ID: brian@gaz-20091002213426-7ojknrpknoedaprl
Merge Monty

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"
 
44
#include <mystrings/m_string.h>
45
45
#include <stdarg.h>
 
46
#include <mysys/my_getopt.h>
46
47
#ifdef HAVE_SYS_VADVISE_H
47
48
#include <sys/vadvise.h>
48
49
#endif
53
54
#include <sys/mman.h>
54
55
#endif
55
56
#include <drizzled/util/test.h>
56
 
#include "drizzled/error.h"
57
57
 
58
58
#include <algorithm>
59
59
 
60
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))
 
61
 
66
62
 
67
63
/* Functions defined in this file */
68
64
 
74
70
static ha_checksum calc_checksum(ha_rows count);
75
71
static int writekeys(MI_SORT_PARAM *sort_param);
76
72
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
 
 
 
73
                          my_off_t pagepos, File new_file);
 
74
extern "C"
 
75
{
 
76
  int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
 
77
  int sort_get_next_record(MI_SORT_PARAM *sort_param);
 
78
  int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b);
 
79
  int sort_key_write(MI_SORT_PARAM *sort_param, const void *a);
 
80
  my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
 
81
                              unsigned char *key);
 
82
  int sort_insert_key(MI_SORT_PARAM  *sort_param,
 
83
                      register SORT_KEY_BLOCKS *key_block,
 
84
                      unsigned char *key, my_off_t prev_block);
 
85
  int sort_delete_record(MI_SORT_PARAM *sort_param);
 
86
}
89
87
/*static int flush_pending_blocks(MI_CHECK *param);*/
90
88
static SORT_KEY_BLOCKS  *alloc_key_blocks(MI_CHECK *param, uint32_t blocks,
91
89
                                          uint32_t buffer_length);
293
291
      If the key cache block size is smaller than block_size, we can so
294
292
      avoid unecessary eviction of cache block.
295
293
    */
296
 
    if (!(buff=key_cache_read(info->s->getKeyCache(),
 
294
    if (!(buff=key_cache_read(info->s->key_cache,
297
295
                              info->s->kfile, next_link, DFLT_INIT_HITS,
298
296
                              (unsigned char*) info->buff, MI_MIN_KEY_BLOCK_LENGTH,
299
297
                              MI_MIN_KEY_BLOCK_LENGTH, 1)))
328
326
  if (!(param->testflag & T_SILENT)) puts("- check file-size");
329
327
 
330
328
  /* The following is needed if called externally (not from myisamchk) */
331
 
  flush_key_blocks(info->s->getKeyCache(),
 
329
  flush_key_blocks(info->s->key_cache,
332
330
                   info->s->kfile, FLUSH_FORCE_WRITE);
333
331
 
334
332
  size= lseek(info->s->kfile, 0, SEEK_END);
459
457
                  llstr(share->state.key_root[key],buff));
460
458
      if (!(param->testflag & T_INFO))
461
459
        return(-1);
462
 
      result= UINT32_MAX;
 
460
      result= -1;
463
461
      continue;
464
462
    }
465
463
    param->key_file_blocks+=keyinfo->block_length;
478
476
                    llstr(info->state->records,buff2));
479
477
        if (!(param->testflag & T_INFO))
480
478
        return(-1);
481
 
        result= UINT32_MAX;
 
479
        result= -1;
482
480
        continue;
483
481
      }
484
482
      if (found_keys - full_text_keys == 1 &&
495
493
          mi_check_print_error(param,"Key 1 doesn't point at all records");
496
494
        if (!(param->testflag & T_INFO))
497
495
          return(-1);
498
 
        result= UINT32_MAX;
 
496
        result= -1;
499
497
        continue;
500
498
      }
501
499
    }
894
892
      puts("- check record links");
895
893
  }
896
894
 
897
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
 
895
  if (!mi_alloc_rec_buff(info, -1, &record))
898
896
  {
899
897
    mi_check_print_error(param,"Not enough memory for record");
900
898
    return(-1);
1265
1263
  free(mi_get_rec_buff_ptr(info, record));
1266
1264
  return (error);
1267
1265
 err:
1268
 
  mi_check_print_error(param,"got error: %d when reading datafile at record: %s",errno, llstr(records,llbuff));
 
1266
  mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff));
1269
1267
 err2:
1270
1268
  free(mi_get_rec_buff_ptr(info, record));
1271
1269
  param->testflag|=T_RETRY_WITHOUT_QUICK;
1313
1311
 
1314
1312
    However, there is an exception. Sometimes MySQL disables non-unique
1315
1313
    indexes when the table is empty (e.g. when copying a table in
1316
 
    drizzled::alter_table()). When enabling the non-unique indexes, they
 
1314
    mysql_alter_table()). When enabling the non-unique indexes, they
1317
1315
    are still empty. So there is no index block that can be lost. This
1318
1316
    optimization is implemented in this function.
1319
1317
 
1362
1360
        Flush dirty blocks of this index file from key cache and remove
1363
1361
        all blocks of this index file from key cache.
1364
1362
      */
1365
 
      error= flush_key_blocks(share->getKeyCache(), share->kfile,
 
1363
      error= flush_key_blocks(share->key_cache, share->kfile,
1366
1364
                              FLUSH_FORCE_WRITE);
1367
1365
      goto end;
1368
1366
    }
1375
1373
  }
1376
1374
 
1377
1375
  /* Remove all key blocks of this index file from key cache. */
1378
 
  if ((error= flush_key_blocks(share->getKeyCache(), share->kfile,
 
1376
  if ((error= flush_key_blocks(share->key_cache, share->kfile,
1379
1377
                               FLUSH_IGNORE_CHANGED)))
1380
1378
    goto end;
1381
1379
 
1406
1404
  int error,got_error;
1407
1405
  ha_rows start_records,new_header_length;
1408
1406
  my_off_t del;
1409
 
  int new_file;
 
1407
  File new_file;
1410
1408
  MYISAM_SHARE *share=info->s;
1411
1409
  char llbuff[22],llbuff2[22];
1412
1410
  SORT_INFO sort_info;
1432
1430
    param->testflag|=T_CALC_CHECKSUM;
1433
1431
 
1434
1432
  if (!param->using_global_keycache)
1435
 
    assert(0);
 
1433
    init_key_cache(dflt_key_cache, param->key_cache_block_size,
 
1434
                   (size_t)param->use_buffers, 0, 0);
1436
1435
 
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)))
 
1436
  if (init_io_cache(&param->read_cache,info->dfile,
 
1437
                    (uint) param->read_buffer_length,
 
1438
                    READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
1438
1439
  {
1439
1440
    memset(&info->rec_cache, 0, sizeof(info->rec_cache));
1440
1441
    goto err;
1441
1442
  }
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
 
    {
 
1443
  if (!rep_quick)
 
1444
    if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
 
1445
                      WRITE_CACHE, new_header_length, 1,
 
1446
                      MYF(MY_WME | MY_WAIT_IF_FULL)))
1446
1447
      goto err;
1447
 
    }
1448
 
  }
1449
1448
  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))
 
1449
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
 
1450
      !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
1452
1451
  {
1453
1452
    mi_check_print_error(param, "Not enough memory for extra record");
1454
1453
    goto err;
1457
1456
  if (!rep_quick)
1458
1457
  {
1459
1458
    /* Get real path for data file */
1460
 
    if ((new_file=my_create(internal::fn_format(param->temp_filename,
 
1459
    if ((new_file=my_create(fn_format(param->temp_filename,
1461
1460
                                      share->data_file_name, "",
1462
1461
                                      DATA_TMP_EXT, 2+4),
1463
1462
                            0,param->tmpfile_createflag,
1513
1512
  {
1514
1513
    if (writekeys(&sort_param))
1515
1514
    {
1516
 
      if (errno != HA_ERR_FOUND_DUPP_KEY)
 
1515
      if (my_errno != HA_ERR_FOUND_DUPP_KEY)
1517
1516
        goto err;
1518
1517
      mi_check_print_info(param,"Duplicate key %2d for record at %10s against new record at %10s",
1519
1518
                          info->errkey+1,
1548
1547
  {
1549
1548
    mi_check_print_warning(param,
1550
1549
                           "Can't change size of indexfile, error: %d",
1551
 
                           errno);
 
1550
                           my_errno);
1552
1551
    goto err;
1553
1552
  }
1554
1553
 
1574
1573
 
1575
1574
  if (!rep_quick)
1576
1575
  {
1577
 
    internal::my_close(info->dfile,MYF(0));
 
1576
    my_close(info->dfile,MYF(0));
1578
1577
    info->dfile=new_file;
1579
1578
    info->state->data_file_length=sort_param.filepos;
1580
1579
    share->state.version=(ulong) time((time_t*) 0);     /* Force reopen */
1607
1606
    /* Replace the actual file with the temporary file */
1608
1607
    if (new_file >= 0)
1609
1608
    {
1610
 
      internal::my_close(new_file,MYF(0));
 
1609
      my_close(new_file,MYF(0));
1611
1610
      info->dfile=new_file= -1;
1612
1611
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
1613
1612
                            DATA_TMP_EXT, share->base.raid_chunks,
1620
1619
  if (got_error)
1621
1620
  {
1622
1621
    if (! param->error_printed)
1623
 
      mi_check_print_error(param,"%d for record at pos %s",errno,
 
1622
      mi_check_print_error(param,"%d for record at pos %s",my_errno,
1624
1623
                  llstr(sort_param.start_recpos,llbuff));
1625
1624
    if (new_file >= 0)
1626
1625
    {
1627
 
      internal::my_close(new_file,MYF(0));
 
1626
      my_close(new_file,MYF(0));
1628
1627
      my_delete(param->temp_filename, MYF(MY_WME));
1629
1628
      info->rec_cache.file=-1; /* don't flush data to new_file, it's closed */
1630
1629
    }
1641
1640
  rec_buff_ptr= NULL;
1642
1641
 
1643
1642
  free(sort_info.buff);
1644
 
  param->read_cache.end_io_cache();
 
1643
  end_io_cache(&param->read_cache);
1645
1644
  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)
 
1645
  end_io_cache(&info->rec_cache);
 
1646
  got_error|=flush_blocks(param, share->key_cache, share->kfile);
 
1647
  if (!got_error && param->testflag & T_UNPACK)
1649
1648
  {
1650
1649
    share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
1651
1650
    share->pack.header_length=0;
1682
1681
  return(0);
1683
1682
 
1684
1683
 err:
1685
 
  if (errno == HA_ERR_FOUND_DUPP_KEY)
 
1684
  if (my_errno == HA_ERR_FOUND_DUPP_KEY)
1686
1685
  {
1687
1686
    info->errkey=(int) i;                       /* This key was found */
1688
1687
    while ( i-- > 0 )
1751
1750
 
1752
1751
        /* Tell system that we want all memory for our cache */
1753
1752
 
1754
 
void lock_memory(MI_CHECK *)
 
1753
void lock_memory(MI_CHECK *param)
1755
1754
{
 
1755
#ifdef SUN_OS                           /* Key-cacheing thrases on sun 4.1 */
 
1756
  if (param->opt_lock_memory)
 
1757
  {
 
1758
    int success = mlockall(MCL_CURRENT);        /* or plock(DATLOCK); */
 
1759
    if (geteuid() == 0 && success != 0)
 
1760
      mi_check_print_warning(param,
 
1761
                             "Failed to lock memory. errno %d",my_errno);
 
1762
  }
 
1763
#else
 
1764
  (void)param;
 
1765
#endif
1756
1766
} /* lock_memory */
1757
1767
 
1758
1768
 
1759
1769
        /* Flush all changed blocks to disk */
1760
1770
 
1761
 
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, int file)
 
1771
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file)
1762
1772
{
1763
1773
  if (flush_key_blocks(key_cache, file, FLUSH_RELEASE))
1764
1774
  {
1765
 
    mi_check_print_error(param,"%d when trying to write bufferts",errno);
 
1775
    mi_check_print_error(param,"%d when trying to write bufferts",my_errno);
1766
1776
    return(1);
1767
1777
  }
1768
1778
  if (!param->using_global_keycache)
1777
1787
{
1778
1788
  register uint32_t key;
1779
1789
  register MI_KEYDEF *keyinfo;
1780
 
  int new_file;
 
1790
  File new_file;
1781
1791
  my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
1782
1792
  uint32_t r_locks,w_locks;
1783
1793
  int old_lock;
1792
1802
    printf("- Sorting index for MyISAM-table '%s'\n",name);
1793
1803
 
1794
1804
  /* 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,
 
1805
  fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32);
 
1806
  if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename,
1797
1807
                                    "", INDEX_TMP_EXT,2+4),
1798
1808
                          0,param->tmpfile_createflag,MYF(0))) <= 0)
1799
1809
  {
1824
1834
  }
1825
1835
 
1826
1836
  /* Flush key cache for this file if we are calling this outside myisamchk */
1827
 
  flush_key_blocks(share->getKeyCache(), share->kfile, FLUSH_IGNORE_CHANGED);
 
1837
  flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED);
1828
1838
 
1829
1839
  share->state.version=(ulong) time((time_t*) 0);
1830
1840
  old_state= share->state;                      /* save state if not stored */
1835
1845
        /* Put same locks as old file */
1836
1846
  share->r_locks= share->w_locks= share->tot_locks= 0;
1837
1847
  (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
1838
 
  internal::my_close(share->kfile,MYF(MY_WME));
 
1848
  my_close(share->kfile,MYF(MY_WME));
1839
1849
  share->kfile = -1;
1840
 
  internal::my_close(new_file,MYF(MY_WME));
 
1850
  my_close(new_file,MYF(MY_WME));
1841
1851
  if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1842
1852
                        MYF(0)) ||
1843
1853
      mi_open_keyfile(share))
1861
1871
  return(0);
1862
1872
 
1863
1873
err:
1864
 
  internal::my_close(new_file,MYF(MY_WME));
 
1874
  my_close(new_file,MYF(MY_WME));
1865
1875
err2:
1866
1876
  my_delete(param->temp_filename,MYF(MY_WME));
1867
1877
  return(-1);
1871
1881
         /* Sort records recursive using one index */
1872
1882
 
1873
1883
static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
1874
 
                          my_off_t pagepos, int new_file)
 
1884
                          my_off_t pagepos, File new_file)
1875
1885
{
1876
1886
  uint32_t length,nod_flag,used_length, key_length;
1877
1887
  unsigned char *buff,*keypos,*endpos;
1922
1932
  if (my_pwrite(new_file,(unsigned char*) buff,(uint) keyinfo->block_length,
1923
1933
                new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
1924
1934
  {
1925
 
    mi_check_print_error(param,"Can't write indexblock, error: %d",errno);
 
1935
    mi_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
1926
1936
    goto err;
1927
1937
  }
1928
1938
  free(buff);
1950
1960
  (void)raid_chunks;
1951
1961
  char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
1952
1962
  /* Get real path to filename */
1953
 
  (void) internal::fn_format(old_filename,filename,"",old_ext,2+4+32);
 
1963
  (void) fn_format(old_filename,filename,"",old_ext,2+4+32);
1954
1964
  return my_redel(old_filename,
1955
 
                  internal::fn_format(new_filename,old_filename,"",new_ext,2+4),
 
1965
                  fn_format(new_filename,old_filename,"",new_ext,2+4),
1956
1966
                  MYF(MY_WME | MY_LINK_WARNING | MyFlags));
1957
1967
} /* change_to_newfile */
1958
1968
 
1960
1970
 
1961
1971
        /* Copy a block between two files */
1962
1972
 
1963
 
int filecopy(MI_CHECK *param, int to,int from,my_off_t start,
 
1973
int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
1964
1974
             my_off_t length, const char *type)
1965
1975
{
1966
1976
  char tmp_buff[IO_SIZE],*buff;
1990
2000
  if (buff != tmp_buff)
1991
2001
    free(buff);
1992
2002
  mi_check_print_error(param,"Can't copy %s to tempfile, error %d",
1993
 
                       type,errno);
 
2003
                       type,my_errno);
1994
2004
  return(1);
1995
2005
}
1996
2006
 
2018
2028
  ulong length;
2019
2029
  ha_rows start_records;
2020
2030
  my_off_t new_header_length,del;
2021
 
  int new_file;
 
2031
  File new_file;
2022
2032
  MI_SORT_PARAM sort_param;
2023
2033
  MYISAM_SHARE *share=info->s;
2024
2034
  HA_KEYSEG *keyseg;
2045
2055
  memset(&sort_info, 0, sizeof(sort_info));
2046
2056
  memset(&sort_param, 0, sizeof(sort_param));
2047
2057
  if (!(sort_info.key_block=
2048
 
        alloc_key_blocks(param, (uint) param->sort_key_blocks, share->base.max_key_block_length))
2049
 
      || param->read_cache.init_io_cache(info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME))
2050
 
      || (! rep_quick && info->rec_cache.init_io_cache(info->dfile, (uint) param->write_buffer_length, WRITE_CACHE,new_header_length,1, MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)))
2051
 
  {
 
2058
        alloc_key_blocks(param,
 
2059
                         (uint) param->sort_key_blocks,
 
2060
                         share->base.max_key_block_length))
 
2061
      || init_io_cache(&param->read_cache,info->dfile,
 
2062
                       (uint) param->read_buffer_length,
 
2063
                       READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
 
2064
      (! rep_quick &&
 
2065
       init_io_cache(&info->rec_cache,info->dfile,
 
2066
                     (uint) param->write_buffer_length,
 
2067
                     WRITE_CACHE,new_header_length,1,
 
2068
                     MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw)))
2052
2069
    goto err;
2053
 
  }
2054
2070
  sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
2055
2071
  info->opt_flag|=WRITE_CACHE_USED;
2056
2072
  info->rec_cache.file=info->dfile;             /* for sort_delete_record */
2057
2073
 
2058
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.record) ||
2059
 
      !mi_alloc_rec_buff(info, SIZE_MAX, &sort_param.rec_buff))
 
2074
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
 
2075
      !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
2060
2076
  {
2061
2077
    mi_check_print_error(param, "Not enough memory for extra record");
2062
2078
    goto err;
2064
2080
  if (!rep_quick)
2065
2081
  {
2066
2082
    /* Get real path for data file */
2067
 
    if ((new_file=my_create(internal::fn_format(param->temp_filename,
 
2083
    if ((new_file=my_create(fn_format(param->temp_filename,
2068
2084
                                      share->data_file_name, "",
2069
2085
                                      DATA_TMP_EXT, 2+4),
2070
2086
                            0,param->tmpfile_createflag,
2185
2201
    }
2186
2202
    /* No need to calculate checksum again. */
2187
2203
    sort_param.calc_checksum= 0;
2188
 
    sort_param.wordroot.free_root(MYF(0));
 
2204
    free_root(&sort_param.wordroot, MYF(0));
2189
2205
 
2190
2206
    /* Set for next loop */
2191
2207
    sort_info.max_records= (ha_rows) info->state->records;
2201
2217
    if (sort_param.fix_datafile)
2202
2218
    {
2203
2219
      param->read_cache.end_of_file=sort_param.filepos;
2204
 
      if (write_data_suffix(&sort_info, 1) || info->rec_cache.end_io_cache())
2205
 
      {
 
2220
      if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
2206
2221
        goto err;
2207
 
      }
2208
2222
      if (param->testflag & T_SAFE_REPAIR)
2209
2223
      {
2210
2224
        /* Don't repair if we loosed more than one row */
2218
2232
        sort_param.filepos;
2219
2233
      /* Only whole records */
2220
2234
      share->state.version=(ulong) time((time_t*) 0);
2221
 
      internal::my_close(info->dfile,MYF(0));
 
2235
      my_close(info->dfile,MYF(0));
2222
2236
      info->dfile=new_file;
2223
2237
      share->data_file_type=sort_info.new_data_file_type;
2224
2238
      share->pack.header_length=(ulong) new_header_length;
2228
2242
      info->state->data_file_length=sort_param.max_pos;
2229
2243
 
2230
2244
    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);
 
2245
    reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
 
2246
                    1,1);
2232
2247
  }
2233
2248
 
2234
2249
  if (param->testflag & T_WRITE_LOOP)
2260
2275
      if (ftruncate(info->dfile, skr))
2261
2276
        mi_check_print_warning(param,
2262
2277
                               "Can't change size of datafile,  error: %d",
2263
 
                               errno);
 
2278
                               my_errno);
2264
2279
  }
2265
2280
  if (param->testflag & T_CALC_CHECKSUM)
2266
2281
    info->state->checksum=param->glob_crc;
2268
2283
  if (ftruncate(share->kfile, info->state->key_file_length))
2269
2284
    mi_check_print_warning(param,
2270
2285
                           "Can't change size of indexfile, error: %d",
2271
 
                           errno);
 
2286
                           my_errno);
2272
2287
 
2273
2288
  if (!(param->testflag & T_SILENT))
2274
2289
  {
2285
2300
    memcpy( &share->state.state, info->state, sizeof(*info->state));
2286
2301
 
2287
2302
err:
2288
 
  got_error|= flush_blocks(param, share->getKeyCache(), share->kfile);
2289
 
  info->rec_cache.end_io_cache();
 
2303
  got_error|= flush_blocks(param, share->key_cache, share->kfile);
 
2304
  end_io_cache(&info->rec_cache);
2290
2305
  if (!got_error)
2291
2306
  {
2292
2307
    /* Replace the actual file with the temporary file */
2293
2308
    if (new_file >= 0)
2294
2309
    {
2295
 
      internal::my_close(new_file,MYF(0));
 
2310
      my_close(new_file,MYF(0));
2296
2311
      info->dfile=new_file= -1;
2297
2312
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
2298
2313
                            DATA_TMP_EXT, share->base.raid_chunks,
2305
2320
  if (got_error)
2306
2321
  {
2307
2322
    if (! param->error_printed)
2308
 
      mi_check_print_error(param,"%d when fixing table",errno);
 
2323
      mi_check_print_error(param,"%d when fixing table",my_errno);
2309
2324
    if (new_file >= 0)
2310
2325
    {
2311
 
      internal::my_close(new_file,MYF(0));
 
2326
      my_close(new_file,MYF(0));
2312
2327
      my_delete(param->temp_filename, MYF(MY_WME));
2313
2328
      if (info->dfile == new_file)
2314
2329
        info->dfile= -1;
2330
2345
 
2331
2346
  free((unsigned char*) sort_info.key_block);
2332
2347
  free(sort_info.buff);
2333
 
  param->read_cache.end_io_cache();
 
2348
  end_io_cache(&param->read_cache);
 
2349
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
 
2350
  if (!got_error && (param->testflag & T_UNPACK))
 
2351
  {
 
2352
    share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD;
 
2353
    share->pack.header_length=0;
 
2354
  }
 
2355
  return(got_error);
 
2356
}
 
2357
 
 
2358
/*
 
2359
  Threaded repair of table using sorting
 
2360
 
 
2361
  SYNOPSIS
 
2362
    mi_repair_parallel()
 
2363
    param               Repair parameters
 
2364
    info                MyISAM handler to repair
 
2365
    name                Name of table (for warnings)
 
2366
    rep_quick           set to <> 0 if we should not change data file
 
2367
 
 
2368
  DESCRIPTION
 
2369
    Same as mi_repair_by_sort but do it multithreaded
 
2370
    Each key is handled by a separate thread.
 
2371
    TODO: make a number of threads a parameter
 
2372
 
 
2373
    In parallel repair we use one thread per index. There are two modes:
 
2374
 
 
2375
    Quick
 
2376
 
 
2377
      Only the indexes are rebuilt. All threads share a read buffer.
 
2378
      Every thread that needs fresh data in the buffer enters the shared
 
2379
      cache lock. The last thread joining the lock reads the buffer from
 
2380
      the data file and wakes all other threads.
 
2381
 
 
2382
    Non-quick
 
2383
 
 
2384
      The data file is rebuilt and all indexes are rebuilt to point to
 
2385
      the new record positions. One thread is the master thread. It
 
2386
      reads from the old data file and writes to the new data file. It
 
2387
      also creates one of the indexes. The other threads read from a
 
2388
      buffer which is filled by the master. If they need fresh data,
 
2389
      they enter the shared cache lock. If the masters write buffer is
 
2390
      full, it flushes it to the new data file and enters the shared
 
2391
      cache lock too. When all threads joined in the lock, the master
 
2392
      copies its write buffer to the read buffer for the other threads
 
2393
      and wakes them.
 
2394
 
 
2395
  RESULT
 
2396
    0   ok
 
2397
    <>0 Error
 
2398
*/
 
2399
 
 
2400
int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
 
2401
                        const char * name, int rep_quick)
 
2402
{
 
2403
  int got_error;
 
2404
  uint32_t i,key, total_key_length, istep;
 
2405
  ulong rec_length;
 
2406
  ha_rows start_records;
 
2407
  my_off_t new_header_length,del;
 
2408
  File new_file;
 
2409
  MI_SORT_PARAM *sort_param=0;
 
2410
  MYISAM_SHARE *share=info->s;
 
2411
  ulong   *rec_per_key_part;
 
2412
  HA_KEYSEG *keyseg;
 
2413
  char llbuff[22];
 
2414
  IO_CACHE new_data_cache; /* For non-quick repair. */
 
2415
  IO_CACHE_SHARE io_share;
 
2416
  SORT_INFO sort_info;
 
2417
  uint64_t key_map= 0;
 
2418
  pthread_attr_t thr_attr;
 
2419
  ulong max_pack_reclength;
 
2420
 
 
2421
  start_records=info->state->records;
 
2422
  got_error=1;
 
2423
  new_file= -1;
 
2424
  new_header_length=(param->testflag & T_UNPACK) ? 0 :
 
2425
    share->pack.header_length;
 
2426
  if (!(param->testflag & T_SILENT))
 
2427
  {
 
2428
    printf("- parallel recovering (with sort) MyISAM-table '%s'\n",name);
 
2429
    printf("Data records: %s\n", llstr(start_records,llbuff));
 
2430
  }
 
2431
  param->testflag|=T_REP; /* for easy checking */
 
2432
 
 
2433
  if (info->s->options & (HA_OPTION_COMPRESS_RECORD))
 
2434
    param->testflag|=T_CALC_CHECKSUM;
 
2435
 
 
2436
  /*
 
2437
    Quick repair (not touching data file, rebuilding indexes):
 
2438
    {
 
2439
      Read  cache is (MI_CHECK *param)->read_cache using info->dfile.
 
2440
    }
 
2441
 
 
2442
    Non-quick repair (rebuilding data file and indexes):
 
2443
    {
 
2444
      Master thread:
 
2445
 
 
2446
        Read  cache is (MI_CHECK *param)->read_cache using info->dfile.
 
2447
        Write cache is (MI_INFO   *info)->rec_cache  using new_file.
 
2448
 
 
2449
      Slave threads:
 
2450
 
 
2451
        Read  cache is new_data_cache synced to master rec_cache.
 
2452
 
 
2453
      The final assignment of the filedescriptor for rec_cache is done
 
2454
      after the cache creation.
 
2455
 
 
2456
      Don't check file size on new_data_cache, as the resulting file size
 
2457
      is not known yet.
 
2458
 
 
2459
      As rec_cache and new_data_cache are synced, write_buffer_length is
 
2460
      used for the read cache 'new_data_cache'. Both start at the same
 
2461
      position 'new_header_length'.
 
2462
    }
 
2463
  */
 
2464
  memset(&sort_info, 0, sizeof(sort_info));
 
2465
  /* Initialize pthread structures before goto err. */
 
2466
  pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
 
2467
  pthread_cond_init(&sort_info.cond, 0);
 
2468
 
 
2469
  if (!(sort_info.key_block=
 
2470
        alloc_key_blocks(param, (uint) param->sort_key_blocks,
 
2471
                         share->base.max_key_block_length)) ||
 
2472
      init_io_cache(&param->read_cache, info->dfile,
 
2473
                    (uint) param->read_buffer_length,
 
2474
                    READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) ||
 
2475
      (!rep_quick &&
 
2476
       (init_io_cache(&info->rec_cache, info->dfile,
 
2477
                      (uint) param->write_buffer_length,
 
2478
                      WRITE_CACHE, new_header_length, 1,
 
2479
                      MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) ||
 
2480
        init_io_cache(&new_data_cache, -1,
 
2481
                      (uint) param->write_buffer_length,
 
2482
                      READ_CACHE, new_header_length, 1,
 
2483
                      MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))))
 
2484
    goto err;
 
2485
  sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
 
2486
  info->opt_flag|=WRITE_CACHE_USED;
 
2487
  info->rec_cache.file=info->dfile;         /* for sort_delete_record */
 
2488
 
 
2489
  if (!rep_quick)
 
2490
  {
 
2491
    /* Get real path for data file */
 
2492
    if ((new_file=my_create(fn_format(param->temp_filename,
 
2493
                                      share->data_file_name, "",
 
2494
                                      DATA_TMP_EXT,
 
2495
                                      2+4),
 
2496
                            0,param->tmpfile_createflag,
 
2497
                            MYF(0))) < 0)
 
2498
    {
 
2499
      mi_check_print_error(param,"Can't create new tempfile: '%s'",
 
2500
                           param->temp_filename);
 
2501
      goto err;
 
2502
    }
 
2503
    if (new_header_length &&
 
2504
        filecopy(param, new_file,info->dfile,0L,new_header_length,
 
2505
                 "datafile-header"))
 
2506
      goto err;
 
2507
    if (param->testflag & T_UNPACK)
 
2508
    {
 
2509
      share->options&= ~HA_OPTION_COMPRESS_RECORD;
 
2510
      mi_int2store(share->state.header.options,share->options);
 
2511
    }
 
2512
    share->state.dellink= HA_OFFSET_ERROR;
 
2513
    info->rec_cache.file=new_file;
 
2514
  }
 
2515
 
 
2516
  info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
 
2517
 
 
2518
  /* Optionally drop indexes and optionally modify the key_map. */
 
2519
  mi_drop_all_indexes(param, info, false);
 
2520
  key_map= share->state.key_map;
 
2521
  if (param->testflag & T_CREATE_MISSING_KEYS)
 
2522
  {
 
2523
    /* Invert the copied key_map to recreate all disabled indexes. */
 
2524
    key_map= ~key_map;
 
2525
  }
 
2526
 
 
2527
  sort_info.info=info;
 
2528
  sort_info.param = param;
 
2529
 
 
2530
  set_data_file_type(&sort_info, share);
 
2531
  sort_info.dupp=0;
 
2532
  sort_info.buff=0;
 
2533
  param->read_cache.end_of_file=sort_info.filelength=
 
2534
    lseek(param->read_cache.file,0L,SEEK_END);
 
2535
 
 
2536
  if (share->data_file_type == DYNAMIC_RECORD)
 
2537
    rec_length=max(share->base.min_pack_length+1,share->base.min_block_length);
 
2538
  else if (share->data_file_type == COMPRESSED_RECORD)
 
2539
    rec_length=share->base.min_block_length;
 
2540
  else
 
2541
    rec_length=share->base.pack_reclength;
 
2542
  /*
 
2543
    +1 below is required hack for parallel repair mode.
 
2544
    The info->state->records value, that is compared later
 
2545
    to sort_info.max_records and cannot exceed it, is
 
2546
    increased in sort_key_write. In mi_repair_by_sort, sort_key_write
 
2547
    is called after sort_key_read, where the comparison is performed,
 
2548
    but in parallel mode master thread can call sort_key_write
 
2549
    before some other repair thread calls sort_key_read.
 
2550
    Furthermore I'm not even sure +1 would be enough.
 
2551
    May be sort_info.max_records shold be always set to max value in
 
2552
    parallel mode.
 
2553
  */
 
2554
  sort_info.max_records=
 
2555
    ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records + 1:
 
2556
     (ha_rows) (sort_info.filelength/rec_length+1));
 
2557
 
 
2558
  del=info->state->del;
 
2559
  param->glob_crc=0;
 
2560
  /* for compressed tables */
 
2561
  max_pack_reclength= share->base.pack_reclength;
 
2562
  if (share->options & HA_OPTION_COMPRESS_RECORD)
 
2563
    set_if_bigger(max_pack_reclength, share->max_pack_length);
 
2564
  if (!(sort_param=(MI_SORT_PARAM *)
 
2565
        malloc(share->base.keys *
 
2566
               (sizeof(MI_SORT_PARAM) + max_pack_reclength))))
 
2567
  {
 
2568
    mi_check_print_error(param,"Not enough memory for key!");
 
2569
    goto err;
 
2570
  }
 
2571
  memset(sort_param, 0, share->base.keys *
 
2572
                        (sizeof(MI_SORT_PARAM) + max_pack_reclength));
 
2573
  total_key_length=0;
 
2574
  rec_per_key_part= param->rec_per_key_part;
 
2575
  info->state->records=info->state->del=share->state.split=0;
 
2576
  info->state->empty=0;
 
2577
 
 
2578
  for (i=key=0, istep=1 ; key < share->base.keys ;
 
2579
       rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
 
2580
  {
 
2581
    sort_param[i].key=key;
 
2582
    sort_param[i].keyinfo=share->keyinfo+key;
 
2583
    sort_param[i].seg=sort_param[i].keyinfo->seg;
 
2584
    /*
 
2585
      Skip this index if it is marked disabled in the copied
 
2586
      (and possibly inverted) key_map.
 
2587
    */
 
2588
    if (! mi_is_key_active(key_map, key))
 
2589
    {
 
2590
      /* Remember old statistics for key */
 
2591
      assert(rec_per_key_part >= param->rec_per_key_part);
 
2592
      memcpy(rec_per_key_part,
 
2593
             (share->state.rec_per_key_part +
 
2594
              (rec_per_key_part - param->rec_per_key_part)),
 
2595
             sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
 
2596
      istep=0;
 
2597
      continue;
 
2598
    }
 
2599
    istep=1;
 
2600
    if ((!(param->testflag & T_SILENT)))
 
2601
      printf ("- Fixing index %d\n",key+1);
 
2602
    {
 
2603
      sort_param[i].key_read=sort_key_read;
 
2604
      sort_param[i].key_write=sort_key_write;
 
2605
    }
 
2606
    sort_param[i].key_cmp=sort_key_cmp;
 
2607
    sort_param[i].lock_in_memory=lock_memory;
 
2608
    sort_param[i].sort_info=&sort_info;
 
2609
    sort_param[i].master=0;
 
2610
    sort_param[i].fix_datafile=0;
 
2611
    sort_param[i].calc_checksum= 0;
 
2612
 
 
2613
    sort_param[i].filepos=new_header_length;
 
2614
    sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
 
2615
 
 
2616
    sort_param[i].record= (((unsigned char *)(sort_param+share->base.keys))+
 
2617
                           (max_pack_reclength * i));
 
2618
    if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff))
 
2619
    {
 
2620
      mi_check_print_error(param,"Not enough memory!");
 
2621
      goto err;
 
2622
    }
 
2623
 
 
2624
    sort_param[i].key_length=share->rec_reflength;
 
2625
    for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END;
 
2626
         keyseg++)
 
2627
    {
 
2628
      sort_param[i].key_length+=keyseg->length;
 
2629
      if (keyseg->flag & HA_SPACE_PACK)
 
2630
        sort_param[i].key_length+=get_pack_length(keyseg->length);
 
2631
      if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
 
2632
        sort_param[i].key_length+=2 + test(keyseg->length >= 127);
 
2633
      if (keyseg->flag & HA_NULL_PART)
 
2634
        sort_param[i].key_length++;
 
2635
    }
 
2636
    total_key_length+=sort_param[i].key_length;
 
2637
  }
 
2638
  sort_info.total_keys=i;
 
2639
  sort_param[0].master= 1;
 
2640
  sort_param[0].fix_datafile= (bool)(! rep_quick);
 
2641
  sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
 
2642
 
 
2643
  sort_info.got_error=0;
 
2644
  pthread_mutex_lock(&sort_info.mutex);
 
2645
 
 
2646
  /*
 
2647
    Initialize the I/O cache share for use with the read caches and, in
 
2648
    case of non-quick repair, the write cache. When all threads join on
 
2649
    the cache lock, the writer copies the write cache contents to the
 
2650
    read caches.
 
2651
  */
 
2652
  if (i > 1)
 
2653
  {
 
2654
    if (rep_quick)
 
2655
      init_io_cache_share(&param->read_cache, &io_share, NULL, i);
 
2656
    else
 
2657
      init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i);
 
2658
  }
 
2659
  else
 
2660
    io_share.total_threads= 0; /* share not used */
 
2661
 
 
2662
  (void) pthread_attr_init(&thr_attr);
 
2663
  (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
 
2664
 
 
2665
  for (i=0 ; i < sort_info.total_keys ; i++)
 
2666
  {
 
2667
    /*
 
2668
      Copy the properly initialized IO_CACHE structure so that every
 
2669
      thread has its own copy. In quick mode param->read_cache is shared
 
2670
      for use by all threads. In non-quick mode all threads but the
 
2671
      first copy the shared new_data_cache, which is synchronized to the
 
2672
      write cache of the first thread. The first thread copies
 
2673
      param->read_cache, which is not shared.
 
2674
    */
 
2675
    sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache :
 
2676
                               new_data_cache);
 
2677
 
 
2678
    /*
 
2679
      two approaches: the same amount of memory for each thread
 
2680
      or the memory for the same number of keys for each thread...
 
2681
      In the second one all the threads will fill their sort_buffers
 
2682
      (and call write_keys) at the same time, putting more stress on i/o.
 
2683
    */
 
2684
    sort_param[i].sortbuff_size=
 
2685
#ifndef USING_SECOND_APPROACH
 
2686
      param->sort_buffer_length/sort_info.total_keys;
 
2687
#else
 
2688
      param->sort_buffer_length*sort_param[i].key_length/total_key_length;
 
2689
#endif
 
2690
    if (pthread_create(&sort_param[i].thr, &thr_attr,
 
2691
                       thr_find_all_keys,
 
2692
                       (void *) (sort_param+i)))
 
2693
    {
 
2694
      mi_check_print_error(param,"Cannot start a repair thread");
 
2695
      /* Cleanup: Detach from the share. Avoid others to be blocked. */
 
2696
      if (io_share.total_threads)
 
2697
        remove_io_thread(&sort_param[i].read_cache);
 
2698
      sort_info.got_error=1;
 
2699
    }
 
2700
    else
 
2701
      sort_info.threads_running++;
 
2702
  }
 
2703
  (void) pthread_attr_destroy(&thr_attr);
 
2704
 
 
2705
  /* waiting for all threads to finish */
 
2706
  while (sort_info.threads_running)
 
2707
    pthread_cond_wait(&sort_info.cond, &sort_info.mutex);
 
2708
  pthread_mutex_unlock(&sort_info.mutex);
 
2709
 
 
2710
  if ((got_error= thr_write_keys(sort_param)))
 
2711
  {
 
2712
    param->retry_repair=1;
 
2713
    goto err;
 
2714
  }
 
2715
  got_error=1;                          /* Assume the following may go wrong */
 
2716
 
 
2717
  if (sort_param[0].fix_datafile)
 
2718
  {
 
2719
    /*
 
2720
      Append some nuls to the end of a memory mapped file. Destroy the
 
2721
      write cache. The master thread did already detach from the share
 
2722
      by remove_io_thread() in sort.c:thr_find_all_keys().
 
2723
    */
 
2724
    if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache))
 
2725
      goto err;
 
2726
    if (param->testflag & T_SAFE_REPAIR)
 
2727
    {
 
2728
      /* Don't repair if we loosed more than one row */
 
2729
      if (info->state->records+1 < start_records)
 
2730
      {
 
2731
        info->state->records=start_records;
 
2732
        goto err;
 
2733
      }
 
2734
    }
 
2735
    share->state.state.data_file_length= info->state->data_file_length=
 
2736
      sort_param->filepos;
 
2737
    /* Only whole records */
 
2738
    share->state.version=(ulong) time((time_t*) 0);
 
2739
 
 
2740
    /*
 
2741
      Exchange the data file descriptor of the table, so that we use the
 
2742
      new file from now on.
 
2743
     */
 
2744
    my_close(info->dfile,MYF(0));
 
2745
    info->dfile=new_file;
 
2746
 
 
2747
    share->data_file_type=sort_info.new_data_file_type;
 
2748
    share->pack.header_length=(ulong) new_header_length;
 
2749
  }
 
2750
  else
 
2751
    info->state->data_file_length=sort_param->max_pos;
 
2752
 
 
2753
  if (rep_quick && del+sort_info.dupp != info->state->del)
 
2754
  {
 
2755
    mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
 
2756
    mi_check_print_error(param,"Run recovery again without -q");
 
2757
    param->retry_repair=1;
 
2758
    param->testflag|=T_RETRY_WITHOUT_QUICK;
 
2759
    goto err;
 
2760
  }
 
2761
 
 
2762
  if (rep_quick & T_FORCE_UNIQUENESS)
 
2763
  {
 
2764
    my_off_t skr=info->state->data_file_length+
 
2765
      (share->options & HA_OPTION_COMPRESS_RECORD ?
 
2766
       MEMMAP_EXTRA_MARGIN : 0);
 
2767
#ifdef USE_RELOC
 
2768
    if (share->data_file_type == STATIC_RECORD &&
 
2769
        skr < share->base.reloc*share->base.min_pack_length)
 
2770
      skr=share->base.reloc*share->base.min_pack_length;
 
2771
#endif
 
2772
    if (skr != sort_info.filelength && !info->s->base.raid_type)
 
2773
      if (ftruncate(info->dfile, skr))
 
2774
        mi_check_print_warning(param,
 
2775
                               "Can't change size of datafile,  error: %d",
 
2776
                               my_errno);
 
2777
  }
 
2778
  if (param->testflag & T_CALC_CHECKSUM)
 
2779
    info->state->checksum=param->glob_crc;
 
2780
 
 
2781
  if (ftruncate(share->kfile, info->state->key_file_length))
 
2782
    mi_check_print_warning(param,
 
2783
                           "Can't change size of indexfile, error: %d", my_errno);
 
2784
 
 
2785
  if (!(param->testflag & T_SILENT))
 
2786
  {
 
2787
    if (start_records != info->state->records)
 
2788
      printf("Data records: %s\n", llstr(info->state->records,llbuff));
 
2789
    if (sort_info.dupp)
 
2790
      mi_check_print_warning(param,
 
2791
                             "%s records have been removed",
 
2792
                             llstr(sort_info.dupp,llbuff));
 
2793
  }
 
2794
  got_error=0;
 
2795
 
 
2796
  if (&share->state.state != info->state)
 
2797
    memcpy(&share->state.state, info->state, sizeof(*info->state));
 
2798
 
 
2799
err:
 
2800
  got_error|= flush_blocks(param, share->key_cache, share->kfile);
 
2801
  /*
 
2802
    Destroy the write cache. The master thread did already detach from
 
2803
    the share by remove_io_thread() or it was not yet started (if the
 
2804
    error happend before creating the thread).
 
2805
  */
 
2806
  end_io_cache(&info->rec_cache);
 
2807
  /*
 
2808
    Destroy the new data cache in case of non-quick repair. All slave
 
2809
    threads did either detach from the share by remove_io_thread()
 
2810
    already or they were not yet started (if the error happend before
 
2811
    creating the threads).
 
2812
  */
 
2813
  if (!rep_quick)
 
2814
    end_io_cache(&new_data_cache);
 
2815
  if (!got_error)
 
2816
  {
 
2817
    /* Replace the actual file with the temporary file */
 
2818
    if (new_file >= 0)
 
2819
    {
 
2820
      my_close(new_file,MYF(0));
 
2821
      info->dfile=new_file= -1;
 
2822
      if (change_to_newfile(share->data_file_name,MI_NAME_DEXT,
 
2823
                            DATA_TMP_EXT, share->base.raid_chunks,
 
2824
                            (param->testflag & T_BACKUP_DATA ?
 
2825
                             MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
 
2826
          mi_open_datafile(info,share,-1))
 
2827
        got_error=1;
 
2828
    }
 
2829
  }
 
2830
  if (got_error)
 
2831
  {
 
2832
    if (! param->error_printed)
 
2833
      mi_check_print_error(param,"%d when fixing table",my_errno);
 
2834
    if (new_file >= 0)
 
2835
    {
 
2836
      my_close(new_file,MYF(0));
 
2837
      my_delete(param->temp_filename, MYF(MY_WME));
 
2838
      if (info->dfile == new_file)
 
2839
        info->dfile= -1;
 
2840
    }
 
2841
    mi_mark_crashed_on_repair(info);
 
2842
  }
 
2843
  else if (key_map == share->state.key_map)
 
2844
    share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
 
2845
  share->state.changed|=STATE_NOT_SORTED_PAGES;
 
2846
 
 
2847
  pthread_cond_destroy (&sort_info.cond);
 
2848
  pthread_mutex_destroy(&sort_info.mutex);
 
2849
 
 
2850
  free((unsigned char*) sort_info.key_block);
 
2851
  free((unsigned char*) sort_param);
 
2852
  free(sort_info.buff);
 
2853
  end_io_cache(&param->read_cache);
2334
2854
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
2335
2855
  if (!got_error && (param->testflag & T_UNPACK))
2336
2856
  {
2361
2881
    (info->s->rec_reflength+
2362
2882
     _mi_make_key(info, sort_param->key, (unsigned char*) key,
2363
2883
                  sort_param->record, sort_param->filepos));
2364
 
#ifdef HAVE_VALGRIND
 
2884
#ifdef HAVE_purify
2365
2885
  memset((unsigned char *)key+sort_param->real_key_length, 0,
2366
2886
         (sort_param->key_length-sort_param->real_key_length));
2367
2887
#endif
2690
3210
        {
2691
3211
          mi_check_print_info(param,
2692
3212
                              "Read error for block at: %s (error: %d); Skipped",
2693
 
                              llstr(block_info.filepos,llbuff),errno);
 
3213
                              llstr(block_info.filepos,llbuff),my_errno);
2694
3214
          goto try_next;
2695
3215
        }
2696
3216
        left_length-=block_info.data_len;
2783
3303
      if (my_b_write(&info->rec_cache,sort_param->record,
2784
3304
                     share->base.pack_reclength))
2785
3305
      {
2786
 
        mi_check_print_error(param,"%d when writing to datafile",errno);
 
3306
        mi_check_print_error(param,"%d when writing to datafile",my_errno);
2787
3307
        return(1);
2788
3308
      }
2789
3309
      sort_param->filepos+=share->base.pack_reclength;
2837
3357
                                  sort_param->filepos+block_length,
2838
3358
                                  &from,&reclength,&flag))
2839
3359
        {
2840
 
          mi_check_print_error(param,"%d when writing to datafile",errno);
 
3360
          mi_check_print_error(param,"%d when writing to datafile",my_errno);
2841
3361
          return(1);
2842
3362
        }
2843
3363
        sort_param->filepos+=block_length;
3152
3672
         (my_off_t) info->s->base.max_data_file_length;
3153
3673
}
3154
3674
 
 
3675
        /* Recreate table with bigger more alloced record-data */
 
3676
 
 
3677
int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
 
3678
{
 
3679
  int error;
 
3680
  MI_INFO info;
 
3681
  MYISAM_SHARE share;
 
3682
  MI_KEYDEF *keyinfo,*key,*key_end;
 
3683
  HA_KEYSEG *keysegs,*keyseg;
 
3684
  MI_COLUMNDEF *recdef,*rec,*end;
 
3685
  MI_UNIQUEDEF *uniquedef,*u_ptr,*u_end;
 
3686
  MI_STATUS_INFO status_info;
 
3687
  uint32_t unpack,key_parts;
 
3688
  ha_rows max_records;
 
3689
  uint64_t file_length,tmp_length;
 
3690
  MI_CREATE_INFO create_info;
 
3691
 
 
3692
  error=1;                                      /* Default error */
 
3693
  info= **org_info;
 
3694
  status_info= (*org_info)->state[0];
 
3695
  info.state= &status_info;
 
3696
  share= *(*org_info)->s;
 
3697
  unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
 
3698
    (param->testflag & T_UNPACK);
 
3699
  if (!(keyinfo=(MI_KEYDEF*) malloc(sizeof(MI_KEYDEF)*share.base.keys)))
 
3700
    return(0);
 
3701
  memcpy(keyinfo,share.keyinfo,sizeof(MI_KEYDEF)*share.base.keys);
 
3702
 
 
3703
  key_parts= share.base.all_key_parts;
 
3704
  if (!(keysegs=(HA_KEYSEG*) malloc(sizeof(HA_KEYSEG)*
 
3705
                                    (key_parts+share.base.keys))))
 
3706
  {
 
3707
    free(keyinfo);
 
3708
    return(1);
 
3709
  }
 
3710
  if (!(recdef=(MI_COLUMNDEF*)
 
3711
        malloc(sizeof(MI_COLUMNDEF)*(share.base.fields+1))))
 
3712
  {
 
3713
    free(keyinfo);
 
3714
    free(keysegs);
 
3715
    return(1);
 
3716
  }
 
3717
  if (!(uniquedef=(MI_UNIQUEDEF*)
 
3718
        malloc(sizeof(MI_UNIQUEDEF)*(share.state.header.uniques+1))))
 
3719
  {
 
3720
    free(recdef);
 
3721
    free(keyinfo);
 
3722
    free(keysegs);
 
3723
    return(1);
 
3724
  }
 
3725
 
 
3726
  /* Copy the column definitions */
 
3727
  memcpy(recdef, share.rec, sizeof(MI_COLUMNDEF)*(share.base.fields+1));
 
3728
  for (rec=recdef,end=recdef+share.base.fields; rec != end ; rec++)
 
3729
  {
 
3730
    if (unpack && !(share.options & HA_OPTION_PACK_RECORD) &&
 
3731
        rec->type != FIELD_BLOB &&
 
3732
        rec->type != FIELD_VARCHAR &&
 
3733
        rec->type != FIELD_CHECK)
 
3734
      rec->type=(int) FIELD_NORMAL;
 
3735
  }
 
3736
 
 
3737
  /* Change the new key to point at the saved key segments */
 
3738
  memcpy(keysegs,share.keyparts,
 
3739
         sizeof(HA_KEYSEG)*(key_parts+share.base.keys+
 
3740
                            share.state.header.uniques));
 
3741
  keyseg=keysegs;
 
3742
  for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
 
3743
  {
 
3744
    key->seg=keyseg;
 
3745
    for (; keyseg->type ; keyseg++)
 
3746
    {
 
3747
      if (param->language)
 
3748
        keyseg->language=param->language;       /* change language */
 
3749
    }
 
3750
    keyseg++;                                   /* Skip end pointer */
 
3751
  }
 
3752
 
 
3753
  /* Copy the unique definitions and change them to point at the new key
 
3754
     segments*/
 
3755
  memcpy(uniquedef,share.uniqueinfo,
 
3756
         sizeof(MI_UNIQUEDEF)*(share.state.header.uniques));
 
3757
  for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques;
 
3758
       u_ptr != u_end ; u_ptr++)
 
3759
  {
 
3760
    u_ptr->seg=keyseg;
 
3761
    keyseg+=u_ptr->keysegs+1;
 
3762
  }
 
3763
  if (share.options & HA_OPTION_COMPRESS_RECORD)
 
3764
    share.base.records=max_records=info.state->records;
 
3765
  else if (share.base.min_pack_length)
 
3766
    max_records=(ha_rows) (lseek(info.dfile,0L,SEEK_END) /
 
3767
                           (ulong) share.base.min_pack_length);
 
3768
  else
 
3769
    max_records=0;
 
3770
  unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
 
3771
    (param->testflag & T_UNPACK);
 
3772
  share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
 
3773
 
 
3774
  file_length=(uint64_t) lseek(info.dfile,0L,SEEK_END);
 
3775
  tmp_length= file_length+file_length/10;
 
3776
  set_if_bigger(file_length,param->max_data_file_length);
 
3777
  set_if_bigger(file_length,tmp_length);
 
3778
  set_if_bigger(file_length,(uint64_t) share.base.max_data_file_length);
 
3779
 
 
3780
  mi_close(*org_info);
 
3781
  memset(&create_info, 0, sizeof(create_info));
 
3782
  create_info.max_rows=max(max_records,share.base.records);
 
3783
  create_info.reloc_rows=share.base.reloc;
 
3784
  create_info.old_options=(share.options |
 
3785
                           (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));
 
3786
 
 
3787
  create_info.data_file_length=file_length;
 
3788
  create_info.auto_increment=share.state.auto_increment;
 
3789
  create_info.language = (param->language ? param->language :
 
3790
                          share.state.header.language);
 
3791
  create_info.key_file_length=  status_info.key_file_length;
 
3792
  /*
 
3793
    Allow for creating an auto_increment key. This has an effect only if
 
3794
    an auto_increment key exists in the original table.
 
3795
  */
 
3796
  create_info.with_auto_increment= true;
 
3797
  /* We don't have to handle symlinks here because we are using
 
3798
     HA_DONT_TOUCH_DATA */
 
3799
  if (mi_create(filename,
 
3800
                share.base.keys - share.state.header.uniques,
 
3801
                keyinfo, share.base.fields, recdef,
 
3802
                share.state.header.uniques, uniquedef,
 
3803
                &create_info,
 
3804
                HA_DONT_TOUCH_DATA))
 
3805
  {
 
3806
    mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno);
 
3807
    goto end;
 
3808
  }
 
3809
  *org_info=mi_open(filename,O_RDWR,
 
3810
                    (param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
 
3811
                    (param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
 
3812
                    HA_OPEN_ABORT_IF_LOCKED);
 
3813
  if (!*org_info)
 
3814
  {
 
3815
    mi_check_print_error(param,"Got error %d when trying to open re-created indexfile",
 
3816
                my_errno);
 
3817
    goto end;
 
3818
  }
 
3819
  /* We are modifing */
 
3820
  (*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
 
3821
  _mi_readinfo(*org_info,F_WRLCK,0);
 
3822
  (*org_info)->state->records=info.state->records;
 
3823
  if (share.state.create_time)
 
3824
    (*org_info)->s->state.create_time=share.state.create_time;
 
3825
  (*org_info)->s->state.unique=(*org_info)->this_unique=
 
3826
    share.state.unique;
 
3827
  (*org_info)->state->checksum=info.state->checksum;
 
3828
  (*org_info)->state->del=info.state->del;
 
3829
  (*org_info)->s->state.dellink=share.state.dellink;
 
3830
  (*org_info)->state->empty=info.state->empty;
 
3831
  (*org_info)->state->data_file_length=info.state->data_file_length;
 
3832
  if (update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
 
3833
                        UPDATE_OPEN_COUNT))
 
3834
    goto end;
 
3835
  error=0;
 
3836
end:
 
3837
  free(uniquedef);
 
3838
  free(keyinfo);
 
3839
  free(recdef);
 
3840
  free(keysegs);
 
3841
  return(error);
 
3842
}
 
3843
 
3155
3844
 
3156
3845
        /* write suffix to data file if neaded */
3157
3846
 
3166
3855
    if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
3167
3856
    {
3168
3857
      mi_check_print_error(sort_info->param,
3169
 
                           "%d when writing to datafile",errno);
 
3858
                           "%d when writing to datafile",my_errno);
3170
3859
      return 1;
3171
3860
    }
3172
3861
    sort_info->param->read_cache.end_of_file+=sizeof(buff);
3231
3920
      return 0;
3232
3921
  }
3233
3922
err:
3234
 
  mi_check_print_error(param,"%d when updating keyfile",errno);
 
3923
  mi_check_print_error(param,"%d when updating keyfile",my_errno);
3235
3924
  return 1;
3236
3925
}
3237
3926
 
3269
3958
    We have to use an allocated buffer instead of info->rec_buff as
3270
3959
    _mi_put_key_in_record() may use info->rec_buff
3271
3960
  */
3272
 
  if (!mi_alloc_rec_buff(info, SIZE_MAX, &record))
 
3961
  if (!mi_alloc_rec_buff(info, -1, &record))
3273
3962
  {
3274
3963
    mi_check_print_error(param,"Not enough memory for extra record");
3275
3964
    return;
3278
3967
  mi_extra(info,HA_EXTRA_KEYREAD,0);
3279
3968
  if (mi_rlast(info, record, info->s->base.auto_key-1))
3280
3969
  {
3281
 
    if (errno != HA_ERR_END_OF_FILE)
 
3970
    if (my_errno != HA_ERR_END_OF_FILE)
3282
3971
    {
3283
3972
      mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
3284
3973
      free(mi_get_rec_buff_ptr(info, record));
3285
 
      mi_check_print_error(param,"%d when reading last record",errno);
 
3974
      mi_check_print_error(param,"%d when reading last record",my_errno);
3286
3975
      return;
3287
3976
    }
3288
3977
    if (!repair_only)