LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_check.c
Test: maria-mtr.html
Date: 2009-03-04 Instrumented lines: 2726
Code covered: 0.6 % Executed lines: 17

       1                 : /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
       2                 : 
       3                 :    This program is free software; you can redistribute it and/or modify
       4                 :    it under the terms of the GNU General Public License as published by
       5                 :    the Free Software Foundation; version 2 of the License.
       6                 : 
       7                 :    This program is distributed in the hope that it will be useful,
       8                 :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9                 :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10                 :    GNU General Public License for more details.
      11                 : 
      12                 :    You should have received a copy of the GNU General Public License
      13                 :    along with this program; if not, write to the Free Software
      14                 :    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
      15                 : 
      16                 : /* Describe, check and repair of MARIA tables */
      17                 : 
      18                 : /*
      19                 :   About checksum calculation.
      20                 : 
      21                 :   There are two types of checksums. Table checksum and row checksum.
      22                 : 
      23                 :   Row checksum is an additional uchar at the end of dynamic length
      24                 :   records. It must be calculated if the table is configured for them.
      25                 :   Otherwise they must not be used. The variable
      26                 :   MYISAM_SHARE::calc_checksum determines if row checksums are used.
      27                 :   MI_INFO::checksum is used as temporary storage during row handling.
      28                 :   For parallel repair we must assure that only one thread can use this
      29                 :   variable. There is no problem on the write side as this is done by one
      30                 :   thread only. But when checking a record after read this could go
      31                 :   wrong. But since all threads read through a common read buffer, it is
      32                 :   sufficient if only one thread checks it.
      33                 : 
      34                 :   Table checksum is an eight uchar value in the header of the index file.
      35                 :   It can be calculated even if row checksums are not used. The variable
      36                 :   MI_CHECK::glob_crc is calculated over all records.
      37                 :   MI_SORT_PARAM::calc_checksum determines if this should be done. This
      38                 :   variable is not part of MI_CHECK because it must be set per thread for
      39                 :   parallel repair. The global glob_crc must be changed by one thread
      40                 :   only. And it is sufficient to calculate the checksum once only.
      41                 : */
      42                 : 
      43                 : #include "ma_ftdefs.h"
      44                 : #include "ma_rt_index.h"
      45                 : #include "ma_blockrec.h"
      46                 : #include "trnman.h"
      47                 : #include "ma_key_recover.h"
      48                 : 
      49                 : #include <stdarg.h>
      50                 : #include <my_getopt.h>
      51                 : #ifdef HAVE_SYS_VADVISE_H
      52                 : #include <sys/vadvise.h>
      53                 : #endif
      54                 : #ifdef HAVE_SYS_MMAN_H
      55                 : #include <sys/mman.h>
      56                 : #endif
      57                 : 
      58                 : /* Functions defined in this file */
      59                 : 
      60                 : static int check_k_link(HA_CHECK *param, MARIA_HA *info, my_off_t next_link);
      61                 : static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
      62                 :                      MARIA_PAGE *page, ha_rows *keys,
      63                 :                      ha_checksum *key_checksum, uint level);
      64                 : static uint isam_key_length(MARIA_HA *info,MARIA_KEYDEF *keyinfo);
      65                 : static ha_checksum calc_checksum(ha_rows count);
      66                 : static int writekeys(MARIA_SORT_PARAM *sort_param);
      67                 : static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
      68                 :                           MARIA_KEYDEF *keyinfo,
      69                 :                           my_off_t pagepos, File new_file);
      70                 : static int sort_key_read(MARIA_SORT_PARAM *sort_param, uchar *key);
      71                 : static int sort_maria_ft_key_read(MARIA_SORT_PARAM *sort_param, uchar *key);
      72                 : static int sort_get_next_record(MARIA_SORT_PARAM *sort_param);
      73                 : static int sort_key_cmp(MARIA_SORT_PARAM *sort_param, const void *a,
      74                 :                         const void *b);
      75                 : static int sort_maria_ft_key_write(MARIA_SORT_PARAM *sort_param,
      76                 :                                    const uchar *a);
      77                 : static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a);
      78                 : static my_off_t get_record_for_key(MARIA_KEYDEF *keyinfo, const uchar *key);
      79                 : static int sort_insert_key(MARIA_SORT_PARAM  *sort_param,
      80                 :                            reg1 SORT_KEY_BLOCKS *key_block,
      81                 :                            const uchar *key, my_off_t prev_block);
      82                 : static int sort_delete_record(MARIA_SORT_PARAM *sort_param);
      83                 : /*static int _ma_flush_pending_blocks(HA_CHECK *param);*/
      84                 : static SORT_KEY_BLOCKS  *alloc_key_blocks(HA_CHECK *param, uint blocks,
      85                 :                                           uint buffer_length);
      86                 : static ha_checksum maria_byte_checksum(const uchar *buf, uint length);
      87                 : static void set_data_file_type(MARIA_SORT_INFO *sort_info, MARIA_SHARE *share);
      88                 : static void restore_data_file_type(MARIA_SHARE *share);
      89                 : static void change_data_file_descriptor(MARIA_HA *info, File new_file);
      90                 : static void unuse_data_file_descriptor(MARIA_HA *info);
      91                 : static int _ma_safe_scan_block_record(MARIA_SORT_INFO *sort_info,
      92                 :                                       MARIA_HA *info, uchar *record);
      93                 : static void copy_data_file_state(MARIA_STATE_INFO *to,
      94                 :                                  MARIA_STATE_INFO *from);
      95                 : static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
      96                 :                                  my_off_t position);
      97                 : static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file);
      98                 : static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
      99                 :                                                  MARIA_HA *info);
     100                 : static TrID max_trid_in_system(void);
     101                 : static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid);
     102                 : void retry_if_quick(MARIA_SORT_PARAM *param, int error);
     103                 : 
     104                 : 
     105                 : /* Initialize check param with default values */
     106                 : 
     107                 : void maria_chk_init(HA_CHECK *param)
     108             112 : {
     109             112 :   bzero((uchar*) param,sizeof(*param));
     110             112 :   param->opt_follow_links=1;
     111             112 :   param->keys_in_use= ~(ulonglong) 0;
     112             112 :   param->search_after_block=HA_OFFSET_ERROR;
     113             112 :   param->auto_increment_value= 0;
     114             112 :   param->use_buffers=USE_BUFFER_INIT;
     115             112 :   param->read_buffer_length=READ_BUFFER_INIT;
     116             112 :   param->write_buffer_length=READ_BUFFER_INIT;
     117             112 :   param->sort_buffer_length=SORT_BUFFER_INIT;
     118             112 :   param->sort_key_blocks=BUFFERS_WHEN_SORTING;
     119             112 :   param->tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
     120             112 :   param->myf_rw=MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL);
     121             112 :   param->start_check_pos=0;
     122             112 :   param->max_record_length= LONGLONG_MAX;
     123             112 :   param->pagecache_block_size= KEY_CACHE_BLOCK_SIZE;
     124             112 :   param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
     125                 : }
     126                 : 
     127                 : 
     128                 : /* Initialize check param and maria handler for check of table */
     129                 : 
     130                 : void maria_chk_init_for_check(HA_CHECK *param, MARIA_HA *info)
     131               0 : {
     132               0 :   param->not_visible_rows_found= 0;
     133               0 :   param->max_found_trid= 0;
     134                 : 
     135                 :   /*
     136                 :     Set up transaction handler so that we can see all rows. When rows is read
     137                 :     we will check the found id against param->max_tried
     138                 :   */
     139               0 :   if (!ma_control_file_inited())
     140               0 :     param->max_trid= 0;                 /* Give warning for first trid found */
     141                 :   else
     142               0 :     param->max_trid= max_trid_in_system();
     143                 : 
     144               0 :   maria_ignore_trids(info);
     145                 : }
     146                 : 
     147                 : 
     148                 :         /* Check the status flags for the table */
     149                 : 
     150                 : int maria_chk_status(HA_CHECK *param, MARIA_HA *info)
     151               0 : {
     152               0 :   MARIA_SHARE *share= info->s;
     153                 : 
     154               0 :   if (maria_is_crashed_on_repair(info))
     155               0 :     _ma_check_print_warning(param,
     156                 :                            "Table is marked as crashed and last repair failed");
     157               0 :   else if (maria_is_crashed(info))
     158               0 :     _ma_check_print_warning(param,
     159                 :                            "Table is marked as crashed");
     160               0 :   if (share->state.open_count != (uint) (share->global_changed ? 1 : 0))
     161                 :   {
     162                 :     /* Don't count this as a real warning, as check can correct this ! */
     163               0 :     uint save=param->warning_printed;
     164               0 :     _ma_check_print_warning(param,
     165                 :                            share->state.open_count==1 ?
     166                 :                            "%d client is using or hasn't closed the table properly" :
     167                 :                            "%d clients are using or haven't closed the table properly",
     168                 :                            share->state.open_count);
     169                 :     /* If this will be fixed by the check, forget the warning */
     170               0 :     if (param->testflag & T_UPDATE_STATE)
     171               0 :       param->warning_printed=save;
     172                 :   }
     173               0 :   return 0;
     174                 : }
     175                 : 
     176                 : /*
     177                 :   Check delete links in row data
     178                 : */
     179                 : 
     180                 : int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
     181                 :                   ulonglong test_flag)
     182               0 : {
     183               0 :   MARIA_SHARE *share= info->s;
     184                 :   reg2 ha_rows i;
     185                 :   uint delete_link_length;
     186                 :   my_off_t empty,next_link,old_link;
     187                 :   char buff[22],buff2[22];
     188               0 :   DBUG_ENTER("maria_chk_del");
     189                 : 
     190               0 :   LINT_INIT(old_link);
     191                 : 
     192               0 :   param->record_checksum=0;
     193                 : 
     194               0 :   if (share->data_file_type == BLOCK_RECORD)
     195               0 :     DBUG_RETURN(0);                             /* No delete links here */
     196                 : 
     197               0 :   delete_link_length=((share->options & HA_OPTION_PACK_RECORD) ? 20 :
     198                 :                       share->rec_reflength+1);
     199                 : 
     200               0 :   if (!(test_flag & T_SILENT))
     201               0 :     puts("- check record delete-chain");
     202                 : 
     203               0 :   next_link=share->state.dellink;
     204               0 :   if (share->state.state.del == 0)
     205                 :   {
     206               0 :     if (test_flag & T_VERBOSE)
     207                 :     {
     208               0 :       puts("No recordlinks");
     209                 :     }
     210                 :   }
     211                 :   else
     212                 :   {
     213               0 :     if (test_flag & T_VERBOSE)
     214               0 :       printf("Recordlinks:    ");
     215               0 :     empty=0;
     216               0 :     for (i= share->state.state.del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
     217                 :     {
     218               0 :       if (*_ma_killed_ptr(param))
     219               0 :         DBUG_RETURN(1);
     220               0 :       if (test_flag & T_VERBOSE)
     221               0 :         printf(" %9s",llstr(next_link,buff));
     222               0 :       if (next_link >= share->state.state.data_file_length)
     223               0 :         goto wrong;
     224               0 :       if (my_pread(info->dfile.file, (uchar*) buff, delete_link_length,
     225                 :                    next_link,MYF(MY_NABP)))
     226                 :       {
     227               0 :         if (test_flag & T_VERBOSE) puts("");
     228               0 :         _ma_check_print_error(param,"Can't read delete-link at filepos: %s",
     229                 :                     llstr(next_link,buff));
     230               0 :         DBUG_RETURN(1);
     231                 :       }
     232               0 :       if (*buff != '\0')
     233                 :       {
     234               0 :         if (test_flag & T_VERBOSE) puts("");
     235               0 :         _ma_check_print_error(param,"Record at pos: %s is not remove-marked",
     236                 :                     llstr(next_link,buff));
     237               0 :         goto wrong;
     238                 :       }
     239               0 :       if (share->options & HA_OPTION_PACK_RECORD)
     240                 :       {
     241               0 :         my_off_t prev_link=mi_sizekorr(buff+12);
     242               0 :         if (empty && prev_link != old_link)
     243                 :         {
     244               0 :           if (test_flag & T_VERBOSE) puts("");
     245               0 :           _ma_check_print_error(param,"Deleted block at %s doesn't point back at previous delete link",llstr(next_link,buff2));
     246               0 :           goto wrong;
     247                 :         }
     248               0 :         old_link=next_link;
     249               0 :         next_link=mi_sizekorr(buff+4);
     250               0 :         empty+=mi_uint3korr(buff+1);
     251                 :       }
     252                 :       else
     253                 :       {
     254               0 :         param->record_checksum+=(ha_checksum) next_link;
     255               0 :         next_link= _ma_rec_pos(share, (uchar *) buff + 1);
     256               0 :         empty+=share->base.pack_reclength;
     257                 :       }
     258                 :     }
     259               0 :     if (share->state.state.del && (test_flag & T_VERBOSE))
     260               0 :       puts("\n");
     261               0 :     if (empty != share->state.state.empty)
     262                 :     {
     263               0 :       _ma_check_print_warning(param,
     264                 :                              "Found %s deleted space in delete link chain. Should be %s",
     265                 :                              llstr(empty,buff2),
     266                 :                              llstr(share->state.state.empty,buff));
     267                 :     }
     268               0 :     if (next_link != HA_OFFSET_ERROR)
     269                 :     {
     270               0 :       _ma_check_print_error(param,
     271                 :                            "Found more than the expected %s deleted rows in delete link chain",
     272                 :                            llstr(share->state.state.del, buff));
     273               0 :       goto wrong;
     274                 :     }
     275               0 :     if (i != 0)
     276                 :     {
     277               0 :       _ma_check_print_error(param,
     278                 :                            "Found %s deleted rows in delete link chain. Should be %s",
     279                 :                            llstr(share->state.state.del - i, buff2),
     280                 :                            llstr(share->state.state.del, buff));
     281               0 :       goto wrong;
     282                 :     }
     283                 :   }
     284               0 :   DBUG_RETURN(0);
     285                 : 
     286               0 : wrong:
     287               0 :   param->testflag|=T_RETRY_WITHOUT_QUICK;
     288               0 :   if (test_flag & T_VERBOSE)
     289               0 :     puts("");
     290               0 :   _ma_check_print_error(param,"record delete-link-chain corrupted");
     291               0 :   DBUG_RETURN(1);
     292                 : } /* maria_chk_del */
     293                 : 
     294                 : 
     295                 : /* Check delete links in index file */
     296                 : 
     297                 : static int check_k_link(HA_CHECK *param, register MARIA_HA *info,
     298                 :                         my_off_t next_link)
     299               0 : {
     300               0 :   MARIA_SHARE *share= info->s;
     301               0 :   uint block_size= share->block_size;
     302                 :   ha_rows records;
     303                 :   char llbuff[21], llbuff2[21];
     304                 :   uchar *buff;
     305               0 :   DBUG_ENTER("check_k_link");
     306                 : 
     307               0 :   if (next_link == HA_OFFSET_ERROR)
     308               0 :     DBUG_RETURN(0);                             /* Avoid printing empty line */
     309                 : 
     310               0 :   records= (ha_rows) (share->state.state.key_file_length / block_size);
     311               0 :   while (next_link != HA_OFFSET_ERROR && records > 0)
     312                 :   {
     313               0 :     if (*_ma_killed_ptr(param))
     314               0 :       DBUG_RETURN(1);
     315               0 :     if (param->testflag & T_VERBOSE)
     316               0 :       printf("%16s",llstr(next_link,llbuff));
     317                 : 
     318                 :     /* Key blocks must lay within the key file length entirely. */
     319               0 :     if (next_link + block_size > share->state.state.key_file_length)
     320                 :     {
     321                 :       /* purecov: begin tested */
     322               0 :       _ma_check_print_error(param, "Invalid key block position: %s  "
     323                 :                             "key block size: %u  file_length: %s",
     324                 :                             llstr(next_link, llbuff), block_size,
     325                 :                             llstr(share->state.state.key_file_length, llbuff2));
     326               0 :       DBUG_RETURN(1);
     327                 :       /* purecov: end */
     328                 :     }
     329                 : 
     330                 :     /* Key blocks must be aligned at block_size */
     331               0 :     if (next_link & (block_size -1))
     332                 :     {
     333                 :       /* purecov: begin tested */
     334               0 :       _ma_check_print_error(param, "Mis-aligned key block: %s  "
     335                 :                             "minimum key block length: %u",
     336                 :                             llstr(next_link, llbuff),
     337                 :                             block_size);
     338               0 :       DBUG_RETURN(1);
     339                 :       /* purecov: end */
     340                 :     }
     341                 : 
     342               0 :     DBUG_ASSERT(share->pagecache->block_size == block_size);
     343               0 :     if (!(buff= pagecache_read(share->pagecache,
     344                 :                                &share->kfile,
     345                 :                                (pgcache_page_no_t) (next_link / block_size),
     346                 :                                DFLT_INIT_HITS,
     347                 :                                info->buff, PAGECACHE_READ_UNKNOWN_PAGE,
     348                 :                                PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
     349                 :     {
     350                 :       /* purecov: begin tested */
     351               0 :       _ma_check_print_error(param, "key cache read error for block: %s",
     352                 :                             llstr(next_link,llbuff));
     353               0 :       DBUG_RETURN(1);
     354                 :       /* purecov: end */
     355                 :     }
     356               0 :     if (_ma_get_keynr(info->s, buff) != MARIA_DELETE_KEY_NR)
     357               0 :       _ma_check_print_error(param, "Page at %s is not delete marked",
     358                 :                             llstr(next_link, llbuff));
     359                 : 
     360               0 :     next_link= mi_sizekorr(buff + share->keypage_header);
     361               0 :     records--;
     362               0 :     param->key_file_blocks+=block_size;
     363                 :   }
     364               0 :   if (param->testflag & T_VERBOSE)
     365                 :   {
     366               0 :     if (next_link != HA_OFFSET_ERROR)
     367               0 :       printf("%16s\n",llstr(next_link,llbuff));
     368                 :     else
     369               0 :       puts("");
     370                 :   }
     371               0 :   DBUG_RETURN (next_link != HA_OFFSET_ERROR);
     372                 : } /* check_k_link */
     373                 : 
     374                 : 
     375                 :         /* Check sizes of files */
     376                 : 
     377                 : int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
     378               0 : {
     379               0 :   MARIA_SHARE *share= info->s;
     380                 :   int error;
     381                 :   register my_off_t skr,size;
     382                 :   char buff[22],buff2[22];
     383               0 :   DBUG_ENTER("maria_chk_size");
     384                 : 
     385               0 :   if (!(param->testflag & T_SILENT))
     386               0 :     puts("- check file-size");
     387                 : 
     388                 :   /*
     389                 :     The following is needed if called externally (not from maria_chk).
     390                 :     To get a correct physical size we need to flush them.
     391                 :   */
     392               0 :   if ((error= _ma_flush_table_files(info,
     393                 :                                     MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
     394                 :                                     FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE)))
     395               0 :     _ma_check_print_error(param, "Failed to flush data or index file");
     396                 : 
     397               0 :   size= my_seek(share->kfile.file, 0L, MY_SEEK_END, MYF(MY_THREADSAFE));
     398               0 :   if ((skr=(my_off_t) share->state.state.key_file_length) != size)
     399                 :   {
     400                 :     /* Don't give error if file generated by mariapack */
     401               0 :     if (skr > size && maria_is_any_key_active(share->state.key_map))
     402                 :     {
     403               0 :       error=1;
     404               0 :       _ma_check_print_error(param,
     405                 :                            "Size of indexfile is: %-8s        Should be: %s",
     406                 :                            llstr(size,buff), llstr(skr,buff2));
     407                 :     }
     408               0 :     else if (!(param->testflag & T_VERY_SILENT))
     409               0 :       _ma_check_print_warning(param,
     410                 :                              "Size of indexfile is: %-8s      Should be: %s",
     411                 :                              llstr(size,buff), llstr(skr,buff2));
     412                 :   }
     413               0 :   if (!(param->testflag & T_VERY_SILENT) &&
     414                 :       ! (share->options & HA_OPTION_COMPRESS_RECORD) &&
     415                 :       ulonglong2double(share->state.state.key_file_length) >
     416                 :       ulonglong2double(share->base.margin_key_file_length)*0.9)
     417               0 :     _ma_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
     418                 :                            llstr(share->state.state.key_file_length,buff),
     419                 :                            llstr(share->base.max_key_file_length-1,buff));
     420                 : 
     421               0 :   size= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
     422               0 :   skr=(my_off_t) share->state.state.data_file_length;
     423               0 :   if (share->options & HA_OPTION_COMPRESS_RECORD)
     424               0 :     skr+= MEMMAP_EXTRA_MARGIN;
     425                 : #ifdef USE_RELOC
     426                 :   if (share->data_file_type == STATIC_RECORD &&
     427                 :       skr < (my_off_t) share->base.reloc*share->base.min_pack_length)
     428                 :     skr=(my_off_t) share->base.reloc*share->base.min_pack_length;
     429                 : #endif
     430               0 :   if (skr != size)
     431                 :   {
     432               0 :     if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
     433                 :     {
     434               0 :       share->state.state.data_file_length=size;      /* Skip other errors */
     435               0 :       error=1;
     436               0 :       _ma_check_print_error(param,"Size of datafile is: %-9s         Should be: %s",
     437                 :                     llstr(size,buff), llstr(skr,buff2));
     438               0 :       param->testflag|=T_RETRY_WITHOUT_QUICK;
     439                 :     }
     440                 :     else
     441                 :     {
     442               0 :       _ma_check_print_warning(param,
     443                 :                              "Size of datafile is: %-9s       Should be: %s",
     444                 :                              llstr(size,buff), llstr(skr,buff2));
     445                 :     }
     446                 :   }
     447               0 :   if (!(param->testflag & T_VERY_SILENT) &&
     448                 :       !(share->options & HA_OPTION_COMPRESS_RECORD) &&
     449                 :       ulonglong2double(share->state.state.data_file_length) >
     450                 :       (ulonglong2double(share->base.max_data_file_length)*0.9))
     451               0 :     _ma_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
     452                 :                            llstr(share->state.state.data_file_length,buff),
     453                 :                            llstr(share->base.max_data_file_length-1,buff2));
     454               0 :   DBUG_RETURN(error);
     455                 : } /* maria_chk_size */
     456                 : 
     457                 : 
     458                 : /* Check keys */
     459                 : 
     460                 : int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
     461               0 : {
     462               0 :   uint key,found_keys=0,full_text_keys=0,result=0;
     463                 :   ha_rows keys;
     464                 :   ha_checksum old_record_checksum,init_checksum;
     465                 :   my_off_t all_keydata,all_totaldata,key_totlength,length;
     466                 :   double  *rec_per_key_part;
     467               0 :   MARIA_SHARE *share= info->s;
     468                 :   MARIA_KEYDEF *keyinfo;
     469                 :   char buff[22],buff2[22];
     470                 :   MARIA_PAGE page;
     471               0 :   DBUG_ENTER("maria_chk_key");
     472                 : 
     473               0 :   if (!(param->testflag & T_SILENT))
     474               0 :     puts("- check key delete-chain");
     475                 : 
     476               0 :   param->key_file_blocks=share->base.keystart;
     477               0 :   if (check_k_link(param, info, share->state.key_del))
     478                 :   {
     479               0 :     if (param->testflag & T_VERBOSE) puts("");
     480               0 :     _ma_check_print_error(param,"key delete-link-chain corrupted");
     481               0 :     DBUG_RETURN(-1);
     482                 :   }
     483                 : 
     484               0 :   if (!(param->testflag & T_SILENT))
     485               0 :     puts("- check index reference");
     486                 : 
     487               0 :   all_keydata=all_totaldata=key_totlength=0;
     488               0 :   init_checksum=param->record_checksum;
     489               0 :   old_record_checksum=0;
     490               0 :   if (share->data_file_type == STATIC_RECORD)
     491               0 :     old_record_checksum= (calc_checksum(share->state.state.records +
     492                 :                                         share->state.state.del-1) *
     493                 :                           share->base.pack_reclength);
     494               0 :   rec_per_key_part= param->new_rec_per_key_part;
     495               0 :   for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
     496               0 :        rec_per_key_part+=keyinfo->keysegs, key++, keyinfo++)
     497                 :   {
     498               0 :     param->key_crc[key]=0;
     499               0 :     if (! maria_is_key_active(share->state.key_map, key))
     500                 :     {
     501                 :       /* Remember old statistics for key */
     502               0 :       memcpy((char*) rec_per_key_part,
     503                 :              (char*) (share->state.rec_per_key_part +
     504                 :                       (uint) (rec_per_key_part - param->new_rec_per_key_part)),
     505                 :              keyinfo->keysegs*sizeof(*rec_per_key_part));
     506               0 :       continue;
     507                 :     }
     508               0 :     found_keys++;
     509                 : 
     510               0 :     param->record_checksum=init_checksum;
     511                 : 
     512               0 :     bzero((char*) &param->unique_count,sizeof(param->unique_count));
     513               0 :     bzero((char*) &param->notnull_count,sizeof(param->notnull_count));
     514                 : 
     515               0 :     if ((!(param->testflag & T_SILENT)))
     516               0 :       printf ("- check data record references index: %d\n",key+1);
     517               0 :     if (keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL))
     518               0 :       full_text_keys++;
     519               0 :     if (share->state.key_root[key] == HA_OFFSET_ERROR)
     520                 :     {
     521               0 :       if (share->state.state.records != 0 && !(keyinfo->flag & HA_FULLTEXT))
     522               0 :         _ma_check_print_error(param, "Key tree %u is empty", key + 1);
     523                 :       goto do_stat;
     524                 :     }
     525               0 :     if (_ma_fetch_keypage(&page, info, keyinfo, share->state.key_root[key],
     526                 :                           PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
     527                 :                           info->buff, 0))
     528                 :     {
     529               0 :       report_keypage_fault(param, info, share->state.key_root[key]);
     530               0 :       if (!(param->testflag & T_INFO))
     531               0 :         DBUG_RETURN(-1);
     532               0 :       result= -1;
     533               0 :       continue;
     534                 :     }
     535               0 :     param->key_file_blocks+=keyinfo->block_length;
     536               0 :     keys=0;
     537               0 :     param->keydata=param->totaldata=0;
     538               0 :     param->key_blocks=0;
     539               0 :     param->max_level=0;
     540               0 :     if (chk_index(param, info,keyinfo, &page, &keys, param->key_crc+key,1))
     541               0 :       DBUG_RETURN(-1);
     542               0 :     if (!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL | HA_RTREE_INDEX)))
     543                 :     {
     544               0 :       if (keys != share->state.state.records)
     545                 :       {
     546               0 :         _ma_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
     547                 :                     llstr(share->state.state.records,buff2));
     548               0 :         if (!(param->testflag & T_INFO))
     549               0 :         DBUG_RETURN(-1);
     550               0 :         result= -1;
     551               0 :         continue;
     552                 :       }
     553               0 :       if ((found_keys - full_text_keys == 1 &&
     554                 :            !(share->data_file_type == STATIC_RECORD)) ||
     555                 :           (param->testflag & T_DONT_CHECK_CHECKSUM))
     556               0 :         old_record_checksum= param->record_checksum;
     557               0 :       else if (old_record_checksum != param->record_checksum)
     558                 :       {
     559               0 :         if (key)
     560               0 :           _ma_check_print_error(param,
     561                 :                                 "Key %u doesn't point at same records as "
     562                 :                                 "key 1",
     563                 :                       key+1);
     564                 :         else
     565               0 :           _ma_check_print_error(param,"Key 1 doesn't point at all records");
     566               0 :         if (!(param->testflag & T_INFO))
     567               0 :           DBUG_RETURN(-1);
     568               0 :         result= -1;
     569               0 :         continue;
     570                 :       }
     571                 :     }
     572               0 :     if ((uint) share->base.auto_key -1 == key)
     573                 :     {
     574                 :       /* Check that auto_increment key is bigger than max key value */
     575                 :       ulonglong auto_increment;
     576               0 :       const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
     577               0 :       info->lastinx=key;
     578               0 :       _ma_read_key_record(info, info->rec_buff, 0);
     579               0 :       auto_increment=
     580                 :         ma_retrieve_auto_increment(info->rec_buff + keyseg->start,
     581                 :                                    keyseg->type);
     582               0 :       if (auto_increment > share->state.auto_increment)
     583                 :       {
     584               0 :         _ma_check_print_warning(param, "Auto-increment value: %s is smaller "
     585                 :                                 "than max used value: %s",
     586                 :                                 llstr(share->state.auto_increment,buff2),
     587                 :                                 llstr(auto_increment, buff));
     588                 :       }
     589               0 :       if (param->testflag & T_AUTO_INC)
     590                 :       {
     591               0 :         set_if_bigger(share->state.auto_increment,
     592                 :                       auto_increment);
     593               0 :         set_if_bigger(share->state.auto_increment,
     594                 :                       param->auto_increment_value);
     595                 :       }
     596                 : 
     597                 :       /* Check that there isn't a row with auto_increment = 0 in the table */
     598               0 :       maria_extra(info,HA_EXTRA_KEYREAD,0);
     599               0 :       bzero(info->lastkey_buff, keyinfo->seg->length);
     600               0 :       if (!maria_rkey(info, info->rec_buff, key,
     601                 :                       info->lastkey_buff,
     602                 :                       (key_part_map) 1, HA_READ_KEY_EXACT))
     603                 :       {
     604                 :         /* Don't count this as a real warning, as maria_chk can't correct it */
     605               0 :         uint save=param->warning_printed;
     606               0 :         _ma_check_print_warning(param, "Found row where the auto_increment "
     607                 :                                 "column has the value 0");
     608               0 :         param->warning_printed=save;
     609                 :       }
     610               0 :       maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
     611                 :     }
     612                 : 
     613               0 :     length=(my_off_t) isam_key_length(info,keyinfo)*keys + param->key_blocks*2;
     614               0 :     if (param->testflag & T_INFO && param->totaldata != 0L && keys != 0L)
     615               0 :       printf("Key: %2d:  Keyblocks used: %3d%%  Packed: %4d%%  Max levels: %2d\n",
     616                 :              key+1,
     617                 :              (int) (my_off_t2double(param->keydata)*100.0/my_off_t2double(param->totaldata)),
     618                 :              (int) ((my_off_t2double(length) - my_off_t2double(param->keydata))*100.0/
     619                 :                     my_off_t2double(length)),
     620                 :              param->max_level);
     621               0 :     all_keydata+=param->keydata; all_totaldata+=param->totaldata; key_totlength+=length;
     622                 : 
     623               0 : do_stat:
     624               0 :     if (param->testflag & T_STATISTICS)
     625               0 :       maria_update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
     626                 :                        param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
     627                 :                        param->notnull_count: NULL,
     628                 :                        (ulonglong)share->state.state.records);
     629                 :   }
     630               0 :   if (param->testflag & T_INFO)
     631                 :   {
     632               0 :     if (all_totaldata != 0L && found_keys > 0)
     633               0 :       printf("Total:    Keyblocks used: %3d%%  Packed: %4d%%\n\n",
     634                 :              (int) (my_off_t2double(all_keydata)*100.0/
     635                 :                     my_off_t2double(all_totaldata)),
     636                 :              (int) ((my_off_t2double(key_totlength) -
     637                 :                      my_off_t2double(all_keydata))*100.0/
     638                 :                      my_off_t2double(key_totlength)));
     639               0 :     else if (all_totaldata != 0L && maria_is_any_key_active(share->state.key_map))
     640               0 :       puts("");
     641                 :   }
     642               0 :   if (param->key_file_blocks != share->state.state.key_file_length &&
     643                 :       share->state.key_map == ~(ulonglong) 0)
     644               0 :     _ma_check_print_warning(param, "Some data are unreferenced in keyfile");
     645               0 :   if (found_keys != full_text_keys)
     646               0 :     param->record_checksum=old_record_checksum-init_checksum;        /* Remove delete links */
     647                 :   else
     648               0 :     param->record_checksum=0;
     649               0 :   DBUG_RETURN(result);
     650                 : } /* maria_chk_key */
     651                 : 
     652                 : 
     653                 : 
     654                 : static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
     655                 :                           MARIA_KEYDEF *keyinfo,
     656                 :                           my_off_t page, uchar *buff, ha_rows *keys,
     657                 :                           ha_checksum *key_checksum, uint level)
     658               0 : {
     659                 :   char llbuff[22],llbuff2[22];
     660               0 :   MARIA_SHARE *share= info->s;
     661                 :   MARIA_PAGE ma_page;
     662               0 :   DBUG_ENTER("chk_index_down");
     663                 : 
     664                 :   /* Key blocks must lay within the key file length entirely. */
     665               0 :   if (page + keyinfo->block_length > share->state.state.key_file_length)
     666                 :   {
     667                 :     /* purecov: begin tested */
     668                 :     /* Give it a chance to fit in the real file size. */
     669                 :     my_off_t max_length= my_seek(info->s->kfile.file, 0L, MY_SEEK_END,
     670               0 :                                  MYF(MY_THREADSAFE));
     671               0 :     _ma_check_print_error(param, "Invalid key block position: %s  "
     672                 :                           "key block size: %u  file_length: %s",
     673                 :                           llstr(page, llbuff), keyinfo->block_length,
     674                 :                           llstr(share->state.state.key_file_length, llbuff2));
     675               0 :     if (page + keyinfo->block_length > max_length)
     676               0 :       goto err;
     677                 :     /* Fix the remembered key file length. */
     678               0 :     share->state.state.key_file_length= (max_length &
     679                 :                                           ~ (my_off_t) (keyinfo->block_length -
     680                 :                                                         1));
     681                 :     /* purecov: end */
     682                 :   }
     683                 : 
     684                 :   /* Key blocks must be aligned at block length */
     685               0 :   if (page & (info->s->block_size -1))
     686                 :   {
     687                 :     /* purecov: begin tested */
     688               0 :     _ma_check_print_error(param, "Mis-aligned key block: %s  "
     689                 :                           "key block length: %u",
     690                 :                           llstr(page, llbuff), info->s->block_size);
     691               0 :     goto err;
     692                 :     /* purecov: end */
     693                 :   }
     694                 : 
     695               0 :   if (_ma_fetch_keypage(&ma_page, info, keyinfo, page,
     696                 :                         PAGECACHE_LOCK_LEFT_UNLOCKED,
     697                 :                         DFLT_INIT_HITS, buff, 0))
     698                 :   {
     699               0 :     report_keypage_fault(param, info, page);
     700               0 :     goto err;
     701                 :   }
     702               0 :   param->key_file_blocks+=keyinfo->block_length;
     703               0 :   if (chk_index(param, info, keyinfo, &ma_page, keys, key_checksum,level))
     704               0 :     goto err;
     705                 : 
     706               0 :   DBUG_RETURN(0);
     707                 : 
     708                 :   /* purecov: begin tested */
     709               0 : err:
     710               0 :   DBUG_RETURN(1);
     711                 :   /* purecov: end */
     712                 : }
     713                 : 
     714                 : 
     715                 : /*
     716                 :   "Ignore NULLs" statistics collection method: process first index tuple.
     717                 : 
     718                 :   SYNOPSIS
     719                 :     maria_collect_stats_nonulls_first()
     720                 :       keyseg   IN     Array of key part descriptions
     721                 :       notnull  INOUT  Array, notnull[i] = (number of {keypart1...keypart_i}
     722                 :                                            tuples that don't contain NULLs)
     723                 :       key      IN     Key values tuple
     724                 : 
     725                 :   DESCRIPTION
     726                 :     Process the first index tuple - find out which prefix tuples don't
     727                 :     contain NULLs, and update the array of notnull counters accordingly.
     728                 : */
     729                 : 
     730                 : static
     731                 : void maria_collect_stats_nonulls_first(HA_KEYSEG *keyseg, ulonglong *notnull,
     732                 :                                        const uchar *key)
     733               0 : {
     734                 :   uint first_null, kp;
     735               0 :   first_null= ha_find_null(keyseg, key) - keyseg;
     736                 :   /*
     737                 :     All prefix tuples that don't include keypart_{first_null} are not-null
     738                 :     tuples (and all others aren't), increment counters for them.
     739                 :   */
     740               0 :   for (kp= 0; kp < first_null; kp++)
     741               0 :     notnull[kp]++;
     742                 : }
     743                 : 
     744                 : 
     745                 : /*
     746                 :   "Ignore NULLs" statistics collection method: process next index tuple.
     747                 : 
     748                 :   SYNOPSIS
     749                 :     maria_collect_stats_nonulls_next()
     750                 :       keyseg   IN     Array of key part descriptions
     751                 :       notnull  INOUT  Array, notnull[i] = (number of {keypart1...keypart_i}
     752                 :                                            tuples that don't contain NULLs)
     753                 :       prev_key IN     Previous key values tuple
     754                 :       last_key IN     Next key values tuple
     755                 : 
     756                 :   DESCRIPTION
     757                 :     Process the next index tuple:
     758                 :     1. Find out which prefix tuples of last_key don't contain NULLs, and
     759                 :        update the array of notnull counters accordingly.
     760                 :     2. Find the first keypart number where the prev_key and last_key tuples
     761                 :        are different(A), or last_key has NULL value(B), and return it, so the
     762                 :        caller can count number of unique tuples for each key prefix. We don't
     763                 :        need (B) to be counted, and that is compensated back in
     764                 :        maria_update_key_parts().
     765                 : 
     766                 :   RETURN
     767                 :     1 + number of first keypart where values differ or last_key tuple has NULL
     768                 : */
     769                 : 
     770                 : static
     771                 : int maria_collect_stats_nonulls_next(HA_KEYSEG *keyseg, ulonglong *notnull,
     772                 :                                      const uchar *prev_key,
     773                 :                                      const uchar *last_key)
     774               0 : {
     775                 :   uint diffs[2];
     776                 :   uint first_null_seg, kp;
     777                 :   HA_KEYSEG *seg;
     778                 : 
     779                 :   /*
     780                 :      Find the first keypart where values are different or either of them is
     781                 :      NULL. We get results in diffs array:
     782                 :      diffs[0]= 1 + number of first different keypart
     783                 :      diffs[1]=offset: (last_key + diffs[1]) points to first value in
     784                 :                       last_key that is NULL or different from corresponding
     785                 :                       value in prev_key.
     786                 :   */
     787               0 :   ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY,
     788                 :              SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diffs);
     789               0 :   seg= keyseg + diffs[0] - 1;
     790                 : 
     791                 :   /* Find first NULL in last_key */
     792               0 :   first_null_seg= ha_find_null(seg, last_key + diffs[1]) - keyseg;
     793               0 :   for (kp= 0; kp < first_null_seg; kp++)
     794               0 :     notnull[kp]++;
     795                 : 
     796                 :   /*
     797                 :     Return 1+ number of first key part where values differ. Don't care if
     798                 :     these were NULLs and not .... We compensate for that in
     799                 :     maria_update_key_parts.
     800                 :   */
     801               0 :   return diffs[0];
     802                 : }
     803                 : 
     804                 : 
     805                 : /* Check if index is ok */
     806                 : 
     807                 : static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
     808                 :                      MARIA_PAGE *anc_page, ha_rows *keys,
     809                 :                      ha_checksum *key_checksum, uint level)
     810               0 : {
     811                 :   int flag;
     812                 :   uint comp_flag, page_flag, nod_flag;
     813                 :   uchar *temp_buff, *keypos, *old_keypos, *endpos;
     814                 :   my_off_t next_page,record;
     815               0 :   MARIA_SHARE *share= info->s;
     816                 :   char llbuff[22];
     817                 :   uint diff_pos[2];
     818                 :   uchar tmp_key_buff[MARIA_MAX_KEY_BUFF];
     819                 :   MARIA_KEY tmp_key;
     820               0 :   DBUG_ENTER("chk_index");
     821               0 :   DBUG_DUMP("buff", anc_page->buff, anc_page->size);
     822                 : 
     823                 :   /* TODO: implement appropriate check for RTree keys */
     824               0 :   if (keyinfo->flag & (HA_SPATIAL | HA_RTREE_INDEX))
     825               0 :     DBUG_RETURN(0);
     826                 : 
     827               0 :   if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
     828                 :   {
     829               0 :     _ma_check_print_error(param,"Not enough memory for keyblock");
     830               0 :     DBUG_RETURN(-1);
     831                 :   }
     832                 : 
     833               0 :   if (keyinfo->flag & HA_NOSAME)
     834                 :   {
     835                 :     /* Not real duplicates */
     836               0 :     comp_flag=SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT;
     837                 :   }
     838                 :   else
     839               0 :     comp_flag=SEARCH_SAME;                      /* Keys in positionorder */
     840                 : 
     841               0 :   page_flag=  anc_page->flag;
     842               0 :   nod_flag=   anc_page->node;
     843               0 :   old_keypos= anc_page->buff + share->keypage_header;
     844               0 :   keypos=     old_keypos + nod_flag;
     845               0 :   endpos=     anc_page->buff + anc_page->size;
     846                 : 
     847               0 :   param->keydata+=   anc_page->size;
     848               0 :   param->totaldata+= keyinfo->block_length;       /* INFO */
     849               0 :   param->key_blocks++;
     850               0 :   if (level > param->max_level)
     851               0 :     param->max_level=level;
     852                 : 
     853               0 :   if (_ma_get_keynr(share, anc_page->buff) !=
     854                 :       (uint) (keyinfo - share->keyinfo))
     855               0 :     _ma_check_print_error(param, "Page at %s is not marked for index %u",
     856                 :                           llstr(anc_page->pos, llbuff),
     857                 :                           (uint) (keyinfo - share->keyinfo));
     858               0 :   if ((page_flag & KEYPAGE_FLAG_HAS_TRANSID) &&
     859                 :       !share->base.born_transactional)
     860                 :   {
     861               0 :     _ma_check_print_error(param,
     862                 :                           "Page at %s is marked with HAS_TRANSID even if "
     863                 :                           "table is not transactional",
     864                 :                           llstr(anc_page->pos, llbuff));
     865                 :   }
     866                 : 
     867               0 :   if (anc_page->size > (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
     868                 :   {
     869               0 :     _ma_check_print_error(param,
     870                 :                           "Page at %s has impossible (too big) pagelength",
     871                 :                           llstr(anc_page->pos, llbuff));
     872               0 :     goto err;
     873                 :   }
     874                 : 
     875               0 :   info->last_key.keyinfo= tmp_key.keyinfo= keyinfo;
     876               0 :   tmp_key.data= tmp_key_buff;
     877                 :   for ( ;; )
     878                 :   {
     879               0 :     if (*_ma_killed_ptr(param))
     880               0 :       goto err;
     881               0 :     if (nod_flag)
     882                 :     {
     883               0 :       next_page= _ma_kpos(nod_flag,keypos);
     884               0 :       if (chk_index_down(param,info,keyinfo,next_page,
     885                 :                          temp_buff,keys,key_checksum,level+1))
     886                 :       {
     887               0 :         DBUG_DUMP("page_data", old_keypos, (uint) (keypos - old_keypos));
     888               0 :         goto err;
     889                 :       }
     890                 :     }
     891               0 :     old_keypos=keypos;
     892               0 :     if (keypos >= endpos ||
     893                 :         !(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos))
     894                 :       break;
     895               0 :     if (keypos > endpos)
     896                 :     {
     897               0 :       _ma_check_print_error(param,
     898                 :                             "Page length and length of keys don't match at "
     899                 :                             "page: %s",
     900                 :                             llstr(anc_page->pos,llbuff));
     901               0 :       goto err;
     902                 :     }
     903               0 :     if (share->data_file_type == BLOCK_RECORD &&
     904                 :         !(page_flag & KEYPAGE_FLAG_HAS_TRANSID) &&
     905                 :         key_has_transid(tmp_key.data + tmp_key.data_length +
     906                 :                         share->rec_reflength-1))
     907                 :     {
     908               0 :       _ma_check_print_error(param,
     909                 :                             "Found key marked for transid on page that is not "
     910                 :                             "marked for transid at: %s",
     911                 :                             llstr(anc_page->pos,llbuff));
     912               0 :       goto err;
     913                 :     }
     914                 : 
     915               0 :     if ((*keys)++ &&
     916                 :         (flag=ha_key_cmp(keyinfo->seg, info->last_key.data, tmp_key.data,
     917                 :                          tmp_key.data_length + tmp_key.ref_length,
     918                 :                          (comp_flag | SEARCH_INSERT | (tmp_key.flag >> 1) |
     919                 :                           info->last_key.flag), diff_pos)) >=0)
     920                 :     {
     921               0 :       DBUG_DUMP_KEY("old", &info->last_key);
     922               0 :       DBUG_DUMP_KEY("new", &tmp_key);
     923               0 :       DBUG_DUMP("new_in_page", old_keypos, (uint) (keypos-old_keypos));
     924                 : 
     925               0 :       if ((comp_flag & SEARCH_FIND) && flag == 0)
     926               0 :         _ma_check_print_error(param,"Found duplicated key at page %s",
     927                 :                               llstr(anc_page->pos,llbuff));
     928                 :       else
     929               0 :         _ma_check_print_error(param,"Key in wrong position at page %s",
     930                 :                               llstr(anc_page->pos,llbuff));
     931                 :       goto err;
     932                 :     }
     933                 : 
     934               0 :     if (param->testflag & T_STATISTICS)
     935                 :     {
     936               0 :       if (*keys != 1L)                          /* not first_key */
     937                 :       {
     938               0 :         if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
     939               0 :           ha_key_cmp(keyinfo->seg, info->last_key.data,
     940                 :                      tmp_key.data, tmp_key.data_length,
     941                 :                      SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
     942                 :                      diff_pos);
     943               0 :         else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
     944                 :         {
     945               0 :           diff_pos[0]= maria_collect_stats_nonulls_next(keyinfo->seg,
     946                 :                                                         param->notnull_count,
     947                 :                                                         info->last_key.data,
     948                 :                                                         tmp_key.data);
     949                 :         }
     950               0 :         param->unique_count[diff_pos[0]-1]++;
     951                 :       }
     952                 :       else
     953                 :       {
     954               0 :         if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
     955               0 :           maria_collect_stats_nonulls_first(keyinfo->seg, param->notnull_count,
     956                 :                                             tmp_key.data);
     957                 :       }
     958                 :     }
     959               0 :     _ma_copy_key(&info->last_key, &tmp_key);
     960               0 :     (*key_checksum)+= maria_byte_checksum(tmp_key.data, tmp_key.data_length);
     961               0 :     record= _ma_row_pos_from_key(&tmp_key);
     962                 : 
     963               0 :     if (keyinfo->flag & HA_FULLTEXT) /* special handling for ft2 */
     964                 :     {
     965                 :       uint off;
     966                 :       int  subkeys;
     967               0 :       get_key_full_length_rdonly(off, tmp_key.data);
     968               0 :       subkeys= ft_sintXkorr(tmp_key.data + off);
     969               0 :       if (subkeys < 0)
     970                 :       {
     971               0 :         ha_rows tmp_keys=0;
     972               0 :         if (chk_index_down(param,info,&share->ft2_keyinfo,record,
     973                 :                            temp_buff,&tmp_keys,key_checksum,1))
     974               0 :           goto err;
     975               0 :         if (tmp_keys + subkeys)
     976                 :         {
     977               0 :           _ma_check_print_error(param,
     978                 :                                "Number of words in the 2nd level tree "
     979                 :                                "does not match the number in the header. "
     980                 :                                "Parent word in on the page %s, offset %u",
     981                 :                                llstr(anc_page->pos,llbuff),
     982                 :                                 (uint) (old_keypos - anc_page->buff));
     983               0 :           goto err;
     984                 :         }
     985               0 :         (*keys)+=tmp_keys-1;
     986               0 :         continue;
     987                 :       }
     988                 :       /* fall through */
     989                 :     }
     990               0 :     if ((share->data_file_type != BLOCK_RECORD &&
     991                 :          record >= share->state.state.data_file_length) ||
     992                 :         (share->data_file_type == BLOCK_RECORD &&
     993                 :          ma_recordpos_to_page(record) * share->base.min_block_length >=
     994                 :          share->state.state.data_file_length))
     995                 :     {
     996                 : #ifndef DBUG_OFF
     997                 :       char llbuff2[22], llbuff3[22];
     998                 : #endif
     999               0 :       _ma_check_print_error(param,
    1000                 :                             "Found key at page %s that points to record "
    1001                 :                             "outside datafile",
    1002                 :                             llstr(anc_page->pos,llbuff));
    1003               0 :       DBUG_PRINT("test",("page: %s  record: %s  filelength: %s",
    1004                 :                          llstr(anc_page->pos,llbuff),llstr(record,llbuff2),
    1005                 :                          llstr(share->state.state.data_file_length,llbuff3)));
    1006               0 :       DBUG_DUMP_KEY("key", &tmp_key);
    1007               0 :       DBUG_DUMP("new_in_page", old_keypos, (uint) (keypos-old_keypos));
    1008               0 :       goto err;
    1009                 :     }
    1010               0 :     param->record_checksum+= (ha_checksum) record;
    1011                 :   }
    1012               0 :   if (keypos != endpos)
    1013                 :   {
    1014               0 :     _ma_check_print_error(param,
    1015                 :                           "Keyblock size at page %s is not correct. "
    1016                 :                           "Block length: %u  key length: %u",
    1017                 :                           llstr(anc_page->pos, llbuff), anc_page->size,
    1018                 :                           (uint) (keypos - anc_page->buff));
    1019               0 :     goto err;
    1020                 :   }
    1021                 :   my_afree(temp_buff);
    1022               0 :   DBUG_RETURN(0);
    1023               0 :  err:
    1024                 :   my_afree(temp_buff);
    1025               0 :   DBUG_RETURN(1);
    1026                 : } /* chk_index */
    1027                 : 
    1028                 : 
    1029                 :         /* Calculate a checksum of 1+2+3+4...N = N*(N+1)/2 without overflow */
    1030                 : 
    1031                 : static ha_checksum calc_checksum(ha_rows count)
    1032               0 : {
    1033                 :   ulonglong sum,a,b;
    1034               0 :   DBUG_ENTER("calc_checksum");
    1035                 : 
    1036               0 :   sum=0;
    1037               0 :   a=count; b=count+1;
    1038               0 :   if (a & 1)
    1039               0 :     b>>=1;
    1040                 :   else
    1041               0 :     a>>=1;
    1042               0 :   while (b)
    1043                 :   {
    1044               0 :     if (b & 1)
    1045               0 :       sum+=a;
    1046               0 :     a<<=1; b>>=1;
    1047                 :   }
    1048               0 :   DBUG_PRINT("exit",("sum: %lx",(ulong) sum));
    1049               0 :   DBUG_RETURN((ha_checksum) sum);
    1050                 : } /* calc_checksum */
    1051                 : 
    1052                 : 
    1053                 :         /* Calc length of key in normal isam */
    1054                 : 
    1055                 : static uint isam_key_length(MARIA_HA *info, register MARIA_KEYDEF *keyinfo)
    1056               0 : {
    1057                 :   uint length;
    1058                 :   HA_KEYSEG *keyseg;
    1059               0 :   DBUG_ENTER("isam_key_length");
    1060                 : 
    1061               0 :   length= info->s->rec_reflength;
    1062               0 :   for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
    1063               0 :     length+= keyseg->length;
    1064                 : 
    1065               0 :   DBUG_PRINT("exit",("length: %d",length));
    1066               0 :   DBUG_RETURN(length);
    1067                 : } /* key_length */
    1068                 : 
    1069                 : 
    1070                 : 
    1071                 : static void record_pos_to_txt(MARIA_HA *info, my_off_t recpos,
    1072                 :                               char *buff)
    1073               0 : {
    1074               0 :   if (info->s->data_file_type != BLOCK_RECORD)
    1075               0 :     llstr(recpos, buff);
    1076                 :   else
    1077                 :   {
    1078               0 :     my_off_t page= ma_recordpos_to_page(recpos);
    1079               0 :     uint row= ma_recordpos_to_dir_entry(recpos);
    1080               0 :     char *end= longlong10_to_str(page, buff, 10);
    1081               0 :     *(end++)= ':';
    1082               0 :     longlong10_to_str(row, end, 10);
    1083                 :   }
    1084                 : }
    1085                 : 
    1086                 : 
    1087                 : /*
    1088                 :   Check that keys in records exist in index tree
    1089                 : 
    1090                 :   SYNOPSIS
    1091                 :   check_keys_in_record()
    1092                 :   param         Check paramenter
    1093                 :   info          Maria handler
    1094                 :   extend        Type of check (extended or normal)
    1095                 :   start_recpos  Position to row
    1096                 :   record        Record buffer
    1097                 : 
    1098                 :   NOTES
    1099                 :     This function also calculates record checksum & number of rows
    1100                 : */
    1101                 : 
    1102                 : static int check_keys_in_record(HA_CHECK *param, MARIA_HA *info, int extend,
    1103                 :                                 my_off_t start_recpos, uchar *record)
    1104               0 : {
    1105               0 :   MARIA_SHARE *share= info->s;
    1106                 :   MARIA_KEYDEF *keyinfo;
    1107                 :   char llbuff[22+4];
    1108                 :   uint keynr;
    1109                 : 
    1110               0 :   param->tmp_record_checksum+= (ha_checksum) start_recpos;
    1111               0 :   param->records++;
    1112               0 :   if (param->testflag & T_WRITE_LOOP && param->records % WRITE_COUNT == 0)
    1113                 :   {
    1114               0 :     printf("%s\r", llstr(param->records, llbuff));
    1115               0 :     VOID(fflush(stdout));
    1116                 :   }
    1117                 : 
    1118                 :   /* Check if keys match the record */
    1119               0 :   for (keynr=0, keyinfo= share->keyinfo; keynr < share->base.keys;
    1120               0 :        keynr++, keyinfo++)
    1121                 :   {
    1122               0 :     if (maria_is_key_active(share->state.key_map, keynr))
    1123                 :     {
    1124                 :       MARIA_KEY key;
    1125               0 :       if (!(keyinfo->flag & HA_FULLTEXT))
    1126                 :       {
    1127               0 :         (*keyinfo->make_key)(info, &key, keynr, info->lastkey_buff, record,
    1128                 :                              start_recpos, 0);
    1129               0 :         if (extend)
    1130                 :         {
    1131                 :           /* We don't need to lock the key tree here as we don't allow
    1132                 :              concurrent threads when running maria_chk
    1133                 :           */
    1134                 :           int search_result=
    1135                 : #ifdef HAVE_RTREE_KEYS
    1136                 :             (keyinfo->flag & (HA_SPATIAL | HA_RTREE_INDEX)) ?
    1137                 :             maria_rtree_find_first(info, &key, MBR_EQUAL | MBR_DATA) :
    1138                 : #endif
    1139               0 :             _ma_search(info, &key, SEARCH_SAME, share->state.key_root[keynr]);
    1140               0 :           if (search_result)
    1141                 :           {
    1142               0 :             record_pos_to_txt(info, start_recpos, llbuff);
    1143               0 :             _ma_check_print_error(param,
    1144                 :                                   "Record at: %14s  "
    1145                 :                                   "Can't find key for index: %2d",
    1146                 :                                   llbuff, keynr+1);
    1147               0 :             if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1148               0 :               return -1;
    1149                 :           }
    1150                 :         }
    1151                 :         else
    1152               0 :           param->tmp_key_crc[keynr]+=
    1153                 :             maria_byte_checksum(key.data, key.data_length);
    1154                 :       }
    1155                 :     }
    1156                 :   }
    1157               0 :   return 0;
    1158                 : }
    1159                 : 
    1160                 : 
    1161                 : /*
    1162                 :   Functions to loop through all rows and check if they are ok
    1163                 : 
    1164                 :   NOTES
    1165                 :     One function for each record format
    1166                 : 
    1167                 :   RESULT
    1168                 :     0  ok
    1169                 :     -1 Interrupted by user
    1170                 :     1  Error
    1171                 : */
    1172                 : 
    1173                 : static int check_static_record(HA_CHECK *param, MARIA_HA *info, int extend,
    1174                 :                                uchar *record)
    1175               0 : {
    1176               0 :   MARIA_SHARE *share= info->s;
    1177                 :   my_off_t start_recpos, pos;
    1178                 :   char llbuff[22];
    1179                 : 
    1180               0 :   pos= 0;
    1181               0 :   while (pos < share->state.state.data_file_length)
    1182                 :   {
    1183               0 :     if (*_ma_killed_ptr(param))
    1184               0 :       return -1;
    1185               0 :     if (my_b_read(&param->read_cache, record,
    1186                 :                   share->base.pack_reclength))
    1187                 :     {
    1188               0 :       _ma_check_print_error(param,
    1189                 :                             "got error: %d when reading datafile at position: "
    1190                 :                             "%s",
    1191                 :                             my_errno, llstr(pos, llbuff));
    1192               0 :       return 1;
    1193                 :     }
    1194               0 :     start_recpos= pos;
    1195               0 :     pos+= share->base.pack_reclength;
    1196               0 :     param->splits++;
    1197               0 :     if (*record == '\0')
    1198                 :     {
    1199               0 :       param->del_blocks++;
    1200               0 :       param->del_length+= share->base.pack_reclength;
    1201               0 :       continue;                                 /* Record removed */
    1202                 :     }
    1203               0 :     param->glob_crc+= _ma_static_checksum(info,record);
    1204               0 :     param->used+= share->base.pack_reclength;
    1205               0 :     if (check_keys_in_record(param, info, extend, start_recpos, record))
    1206               0 :       return 1;
    1207                 :   }
    1208               0 :   return 0;
    1209                 : }
    1210                 : 
    1211                 : 
    1212                 : static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
    1213                 :                                 uchar *record)
    1214               0 : {
    1215                 :   MARIA_BLOCK_INFO block_info;
    1216               0 :   MARIA_SHARE *share= info->s;
    1217                 :   my_off_t start_recpos, start_block, pos;
    1218                 :   uchar *to;
    1219                 :   ulong left_length;
    1220                 :   uint  b_type;
    1221                 :   char llbuff[22],llbuff2[22],llbuff3[22];
    1222               0 :   DBUG_ENTER("check_dynamic_record");
    1223                 : 
    1224               0 :   LINT_INIT(left_length);
    1225               0 :   LINT_INIT(start_recpos);
    1226               0 :   LINT_INIT(to);
    1227                 : 
    1228               0 :   pos= 0;
    1229               0 :   while (pos < share->state.state.data_file_length)
    1230                 :   {
    1231               0 :     my_bool got_error= 0;
    1232                 :     int flag;
    1233               0 :     if (*_ma_killed_ptr(param))
    1234               0 :       DBUG_RETURN(-1);
    1235                 : 
    1236               0 :     flag= block_info.second_read=0;
    1237               0 :     block_info.next_filepos=pos;
    1238                 :     do
    1239                 :     {
    1240               0 :       if (_ma_read_cache(&param->read_cache, block_info.header,
    1241                 :                          (start_block=block_info.next_filepos),
    1242                 :                          sizeof(block_info.header),
    1243                 :                          (flag ? 0 : READING_NEXT) | READING_HEADER))
    1244                 :       {
    1245               0 :         _ma_check_print_error(param,
    1246                 :                               "got error: %d when reading datafile at "
    1247                 :                               "position: %s",
    1248                 :                               my_errno, llstr(start_block, llbuff));
    1249               0 :         DBUG_RETURN(1);
    1250                 :       }
    1251                 : 
    1252               0 :       if (start_block & (MARIA_DYN_ALIGN_SIZE-1))
    1253                 :       {
    1254               0 :         _ma_check_print_error(param,"Wrong aligned block at %s",
    1255                 :                               llstr(start_block,llbuff));
    1256               0 :         DBUG_RETURN(1);
    1257                 :       }
    1258               0 :       b_type= _ma_get_block_info(&block_info,-1,start_block);
    1259               0 :       if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
    1260                 :                     BLOCK_FATAL_ERROR))
    1261                 :       {
    1262               0 :         if (b_type & BLOCK_SYNC_ERROR)
    1263                 :         {
    1264               0 :           if (flag)
    1265                 :           {
    1266               0 :             _ma_check_print_error(param,"Unexpected byte: %d at link: %s",
    1267                 :                                   (int) block_info.header[0],
    1268                 :                                   llstr(start_block,llbuff));
    1269               0 :             DBUG_RETURN(1);
    1270                 :           }
    1271               0 :           pos=block_info.filepos+block_info.block_len;
    1272               0 :           goto next;
    1273                 :         }
    1274               0 :         if (b_type & BLOCK_DELETED)
    1275                 :         {
    1276               0 :           if (block_info.block_len < share->base.min_block_length)
    1277                 :           {
    1278               0 :             _ma_check_print_error(param,
    1279                 :                                   "Deleted block with impossible length %lu "
    1280                 :                                   "at %s",
    1281                 :                                   block_info.block_len,llstr(pos,llbuff));
    1282               0 :             DBUG_RETURN(1);
    1283                 :           }
    1284               0 :           if ((block_info.next_filepos != HA_OFFSET_ERROR &&
    1285                 :                block_info.next_filepos >= share->state.state.data_file_length) ||
    1286                 :               (block_info.prev_filepos != HA_OFFSET_ERROR &&
    1287                 :                block_info.prev_filepos >= share->state.state.data_file_length))
    1288                 :           {
    1289               0 :             _ma_check_print_error(param,"Delete link points outside datafile "
    1290                 :                                   "at %s",
    1291                 :                                   llstr(pos,llbuff));
    1292               0 :             DBUG_RETURN(1);
    1293                 :           }
    1294               0 :           param->del_blocks++;
    1295               0 :           param->del_length+= block_info.block_len;
    1296               0 :           param->splits++;
    1297               0 :           pos= block_info.filepos+block_info.block_len;
    1298               0 :           goto next;
    1299                 :         }
    1300               0 :         _ma_check_print_error(param,"Wrong bytesec: %d-%d-%d at linkstart: %s",
    1301                 :                               block_info.header[0],block_info.header[1],
    1302                 :                               block_info.header[2],
    1303                 :                               llstr(start_block,llbuff));
    1304               0 :         DBUG_RETURN(1);
    1305                 :       }
    1306               0 :       if (share->state.state.data_file_length < block_info.filepos+
    1307                 :           block_info.block_len)
    1308                 :       {
    1309               0 :         _ma_check_print_error(param,
    1310                 :                               "Recordlink that points outside datafile at %s",
    1311                 :                               llstr(pos,llbuff));
    1312               0 :         got_error=1;
    1313               0 :         break;
    1314                 :       }
    1315               0 :       param->splits++;
    1316               0 :       if (!flag++)                              /* First block */
    1317                 :       {
    1318               0 :         start_recpos=pos;
    1319               0 :         pos=block_info.filepos+block_info.block_len;
    1320               0 :         if (block_info.rec_len > (uint) share->base.max_pack_length)
    1321                 :         {
    1322               0 :           _ma_check_print_error(param,"Found too long record (%lu) at %s",
    1323                 :                                 (ulong) block_info.rec_len,
    1324                 :                                 llstr(start_recpos,llbuff));
    1325               0 :           got_error=1;
    1326               0 :           break;
    1327                 :         }
    1328               0 :         if (share->base.blobs)
    1329                 :         {
    1330               0 :           if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
    1331                 :                                block_info.rec_len +
    1332                 :                                share->base.extra_rec_buff_size))
    1333                 : 
    1334                 :           {
    1335               0 :             _ma_check_print_error(param,
    1336                 :                                   "Not enough memory (%lu) for blob at %s",
    1337                 :                                   (ulong) block_info.rec_len,
    1338                 :                                   llstr(start_recpos,llbuff));
    1339               0 :             got_error=1;
    1340               0 :             break;
    1341                 :           }
    1342                 :         }
    1343               0 :         to= info->rec_buff;
    1344               0 :         left_length= block_info.rec_len;
    1345                 :       }
    1346               0 :       if (left_length < block_info.data_len)
    1347                 :       {
    1348               0 :         _ma_check_print_error(param,"Found too long record (%lu) at %s",
    1349                 :                               (ulong) block_info.data_len,
    1350                 :                               llstr(start_recpos,llbuff));
    1351               0 :         got_error=1;
    1352               0 :         break;
    1353                 :       }
    1354               0 :       if (_ma_read_cache(&param->read_cache, to, block_info.filepos,
    1355                 :                          (uint) block_info.data_len,
    1356                 :                          flag == 1 ? READING_NEXT : 0))
    1357                 :       {
    1358               0 :         _ma_check_print_error(param,
    1359                 :                               "got error: %d when reading datafile at "
    1360                 :                               "position: %s", my_errno,
    1361                 :                               llstr(block_info.filepos, llbuff));
    1362                 : 
    1363               0 :         DBUG_RETURN(1);
    1364                 :       }
    1365               0 :       to+=block_info.data_len;
    1366               0 :       param->link_used+= block_info.filepos-start_block;
    1367               0 :       param->used+= block_info.filepos - start_block + block_info.data_len;
    1368               0 :       param->empty+= block_info.block_len-block_info.data_len;
    1369               0 :       left_length-= block_info.data_len;
    1370               0 :       if (left_length)
    1371                 :       {
    1372               0 :         if (b_type & BLOCK_LAST)
    1373                 :         {
    1374               0 :           _ma_check_print_error(param,
    1375                 :                                 "Wrong record length %s of %s at %s",
    1376                 :                                 llstr(block_info.rec_len-left_length,llbuff),
    1377                 :                                 llstr(block_info.rec_len, llbuff2),
    1378                 :                                 llstr(start_recpos,llbuff3));
    1379               0 :           got_error=1;
    1380               0 :           break;
    1381                 :         }
    1382               0 :         if (share->state.state.data_file_length < block_info.next_filepos)
    1383                 :         {
    1384               0 :           _ma_check_print_error(param,
    1385                 :                                 "Found next-recordlink that points outside "
    1386                 :                                 "datafile at %s",
    1387                 :                                 llstr(block_info.filepos,llbuff));
    1388               0 :           got_error=1;
    1389               0 :           break;
    1390                 :         }
    1391                 :       }
    1392               0 :     } while (left_length);
    1393                 : 
    1394               0 :     if (! got_error)
    1395                 :     {
    1396               0 :       if (_ma_rec_unpack(info,record,info->rec_buff,block_info.rec_len) ==
    1397                 :           MY_FILE_ERROR)
    1398                 :       {
    1399               0 :         _ma_check_print_error(param,"Found wrong record at %s",
    1400                 :                               llstr(start_recpos,llbuff));
    1401               0 :         got_error=1;
    1402                 :       }
    1403                 :       else
    1404                 :       {
    1405               0 :         ha_checksum checksum= 0;
    1406               0 :         if (share->calc_checksum)
    1407               0 :           checksum= (*share->calc_checksum)(info, record);
    1408                 : 
    1409               0 :         if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE))
    1410                 :         {
    1411               0 :           if (_ma_rec_check(info,record, info->rec_buff,block_info.rec_len,
    1412                 :                             test(share->calc_checksum), checksum))
    1413                 :           {
    1414               0 :             _ma_check_print_error(param,"Found wrong packed record at %s",
    1415                 :                                   llstr(start_recpos,llbuff));
    1416               0 :             got_error= 1;
    1417                 :           }
    1418                 :         }
    1419               0 :         param->glob_crc+= checksum;
    1420                 :       }
    1421                 : 
    1422               0 :       if (! got_error)
    1423                 :       {
    1424               0 :         if (check_keys_in_record(param, info, extend, start_recpos, record))
    1425               0 :           DBUG_RETURN(1);
    1426                 :       }
    1427                 :       else
    1428                 :       {
    1429               0 :         if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1430               0 :           DBUG_RETURN(1);
    1431                 :       }
    1432                 :     }
    1433               0 :     else if (!flag)
    1434               0 :       pos= block_info.filepos+block_info.block_len;
    1435               0 : next:;
    1436                 :   }
    1437               0 :   DBUG_RETURN(0);
    1438                 : }
    1439                 : 
    1440                 : 
    1441                 : static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend,
    1442                 :                                    uchar *record)
    1443               0 : {
    1444                 :   MARIA_BLOCK_INFO block_info;
    1445               0 :   MARIA_SHARE *share= info->s;
    1446                 :   my_off_t start_recpos, pos;
    1447                 :   char llbuff[22];
    1448               0 :   my_bool got_error= 0;
    1449               0 :   DBUG_ENTER("check_compressed_record");
    1450                 : 
    1451               0 :   pos= share->pack.header_length;             /* Skip header */
    1452               0 :   while (pos < share->state.state.data_file_length)
    1453                 :   {
    1454               0 :     if (*_ma_killed_ptr(param))
    1455               0 :       DBUG_RETURN(-1);
    1456                 : 
    1457               0 :     if (_ma_read_cache(&param->read_cache, block_info.header, pos,
    1458                 :                        share->pack.ref_length, READING_NEXT))
    1459                 :     {
    1460               0 :       _ma_check_print_error(param,
    1461                 :                             "got error: %d when reading datafile at position: "
    1462                 :                             "%s",
    1463                 :                             my_errno, llstr(pos, llbuff));
    1464               0 :       DBUG_RETURN(1);
    1465                 :     }
    1466                 : 
    1467               0 :     start_recpos= pos;
    1468               0 :     param->splits++;
    1469               0 :     VOID(_ma_pack_get_block_info(info, &info->bit_buff, &block_info,
    1470                 :                                  &info->rec_buff, &info->rec_buff_size, -1,
    1471                 :                                  start_recpos));
    1472               0 :     pos=block_info.filepos+block_info.rec_len;
    1473               0 :     if (block_info.rec_len < (uint) share->min_pack_length ||
    1474                 :         block_info.rec_len > (uint) share->max_pack_length)
    1475                 :     {
    1476               0 :       _ma_check_print_error(param,
    1477                 :                             "Found block with wrong recordlength: %lu at %s",
    1478                 :                             block_info.rec_len, llstr(start_recpos,llbuff));
    1479               0 :       got_error=1;
    1480               0 :       goto end;
    1481                 :     }
    1482               0 :     if (_ma_read_cache(&param->read_cache, info->rec_buff,
    1483                 :                        block_info.filepos, block_info.rec_len, READING_NEXT))
    1484                 :     {
    1485               0 :       _ma_check_print_error(param,
    1486                 :                             "got error: %d when reading datafile at position: "
    1487                 :                             "%s",
    1488                 :                             my_errno, llstr(block_info.filepos, llbuff));
    1489               0 :       DBUG_RETURN(1);
    1490                 :     }
    1491               0 :     if (_ma_pack_rec_unpack(info, &info->bit_buff, record,
    1492                 :                             info->rec_buff, block_info.rec_len))
    1493                 :     {
    1494               0 :       _ma_check_print_error(param,"Found wrong record at %s",
    1495                 :                             llstr(start_recpos,llbuff));
    1496               0 :       got_error=1;
    1497               0 :       goto end;
    1498                 :     }
    1499               0 :     param->glob_crc+= (*share->calc_checksum)(info,record);
    1500               0 :     param->link_used+= (block_info.filepos - start_recpos);
    1501               0 :     param->used+= (pos-start_recpos);
    1502                 : 
    1503               0 : end:
    1504               0 :     if (! got_error)
    1505                 :     {
    1506               0 :       if (check_keys_in_record(param, info, extend, start_recpos, record))
    1507               0 :         DBUG_RETURN(1);
    1508                 :     }
    1509                 :     else
    1510                 :     {
    1511               0 :       got_error= 0;                             /* Reset for next loop */
    1512               0 :       if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1513               0 :         DBUG_RETURN(1);
    1514                 :     }
    1515                 :   }
    1516               0 :   DBUG_RETURN(0);
    1517                 : }
    1518                 : 
    1519                 : 
    1520                 : /*
    1521                 :   Check if layout on head or tail page is ok
    1522                 : 
    1523                 :   NOTES
    1524                 :     This is for rows-in-block format.
    1525                 : */
    1526                 : 
    1527                 : static int check_page_layout(HA_CHECK *param, MARIA_HA *info,
    1528                 :                              my_off_t page_pos, uchar *page,
    1529                 :                              uint row_count, uint head_empty,
    1530                 :                              uint *real_rows_found, uint *free_slots_found)
    1531               0 : {
    1532                 :   uint empty, last_row_end, row, first_dir_entry, free_entry, block_size;
    1533                 :   uint free_entries, prev_free_entry;
    1534                 :   uchar *dir_entry;
    1535                 :   char llbuff[22];
    1536               0 :   my_bool error_in_free_list= 0;
    1537               0 :   DBUG_ENTER("check_page_layout");
    1538                 : 
    1539               0 :   block_size= info->s->block_size;
    1540               0 :   empty= 0;
    1541               0 :   last_row_end= PAGE_HEADER_SIZE;
    1542               0 :   *real_rows_found= 0;
    1543                 : 
    1544                 :   /* Check free directory list */
    1545               0 :   free_entry= (uint) page[DIR_FREE_OFFSET];
    1546               0 :   free_entries= 0;
    1547               0 :   prev_free_entry= END_OF_DIR_FREE_LIST;
    1548               0 :   while (free_entry != END_OF_DIR_FREE_LIST)
    1549                 :   {
    1550                 :     uchar *dir;
    1551               0 :     if (free_entry > row_count)
    1552                 :     {
    1553               0 :       _ma_check_print_error(param,
    1554                 :                             "Page %9s:  Directory free entry points outside "
    1555                 :                             "directory",
    1556                 :                             llstr(page_pos, llbuff));
    1557               0 :       error_in_free_list= 1;
    1558               0 :       break;
    1559                 :     }
    1560               0 :     dir= dir_entry_pos(page, block_size, free_entry);
    1561               0 :     if (uint2korr(dir) != 0)
    1562                 :     {
    1563               0 :       _ma_check_print_error(param,
    1564                 :                             "Page %9s:  Directory free entry points to "
    1565                 :                             "not deleted entry",
    1566                 :                             llstr(page_pos, llbuff));
    1567               0 :       error_in_free_list= 1;
    1568               0 :       break;
    1569                 :     }
    1570               0 :     if (dir[2] != prev_free_entry)
    1571                 :     {
    1572               0 :       _ma_check_print_error(param,
    1573                 :                             "Page %9s:  Directory free list back pointer "
    1574                 :                             "points to wrong entry",
    1575                 :                             llstr(page_pos, llbuff));
    1576               0 :       error_in_free_list= 1;
    1577               0 :       break;
    1578                 :     }
    1579               0 :     prev_free_entry= free_entry;
    1580               0 :     free_entry= dir[3];
    1581               0 :     free_entries++;
    1582                 :   }
    1583               0 :   *free_slots_found= free_entries;
    1584                 : 
    1585                 :   /* Check directry */
    1586               0 :   dir_entry= page+ block_size - PAGE_SUFFIX_SIZE;
    1587               0 :   first_dir_entry= (block_size - row_count * DIR_ENTRY_SIZE -
    1588                 :                     PAGE_SUFFIX_SIZE);
    1589               0 :   for (row= 0 ; row < row_count ; row++)
    1590                 :   {
    1591                 :     uint pos, length;
    1592               0 :     dir_entry-= DIR_ENTRY_SIZE;
    1593               0 :     pos= uint2korr(dir_entry);
    1594               0 :     if (!pos)
    1595                 :     {
    1596               0 :       free_entries--;
    1597               0 :       if (row == row_count -1)
    1598                 :       {
    1599               0 :         _ma_check_print_error(param,
    1600                 :                               "Page %9s:  First entry in directory is 0",
    1601                 :                               llstr(page_pos, llbuff));
    1602               0 :         if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1603               0 :           DBUG_RETURN(1);
    1604                 :       }
    1605                 :       continue;                                 /* Deleted row */
    1606                 :     }
    1607               0 :     (*real_rows_found)++;
    1608               0 :     length= uint2korr(dir_entry+2);
    1609               0 :     param->used+= length;
    1610               0 :     if (pos < last_row_end)
    1611                 :     {
    1612               0 :       _ma_check_print_error(param,
    1613                 :                             "Page %9s:  Row %3u overlapps with previous row",
    1614                 :                             llstr(page_pos, llbuff), row);
    1615               0 :       DBUG_RETURN(1);
    1616                 :     }
    1617               0 :     empty+= (pos - last_row_end);
    1618               0 :     last_row_end= pos + length;
    1619               0 :     if (last_row_end > first_dir_entry)
    1620                 :     {
    1621               0 :       _ma_check_print_error(param,
    1622                 :                             "Page %9s:  Row %3u overlapps with directory",
    1623                 :                             llstr(page_pos, llbuff), row);
    1624               0 :       DBUG_RETURN(1);
    1625                 :     }
    1626                 :   }
    1627               0 :   empty+= (first_dir_entry - last_row_end);
    1628                 : 
    1629               0 :   if (empty != head_empty)
    1630                 :   {
    1631               0 :     _ma_check_print_error(param,
    1632                 :                           "Page %9s:  Wrong empty size.  Stored: %5u  "
    1633                 :                           "Actual: %5u",
    1634                 :                           llstr(page_pos, llbuff), head_empty, empty);
    1635               0 :     param->err_count++;
    1636                 :   }
    1637               0 :   if (free_entries != 0 && !error_in_free_list)
    1638                 :   {
    1639               0 :     _ma_check_print_error(param,
    1640                 :                           "Page %9s:  Directory free link don't include "
    1641                 :                           "all free entries",
    1642                 :                           llstr(page_pos, llbuff));
    1643               0 :     param->err_count++;
    1644                 :   }
    1645               0 :   DBUG_RETURN(param->err_count &&
    1646                 :               (param->err_count >= MAXERR || !(param->testflag & T_VERBOSE)));
    1647                 : }
    1648                 : 
    1649                 : 
    1650                 : /*
    1651                 :   Check all rows on head page
    1652                 : 
    1653                 :   NOTES
    1654                 :     This is for rows-in-block format.
    1655                 : 
    1656                 :     Before this, we have already called check_page_layout(), so
    1657                 :     we know the block is logicaly correct (even if the rows may not be that)
    1658                 : 
    1659                 :   RETURN
    1660                 :    0  ok
    1661                 :    1  error
    1662                 : */
    1663                 : 
    1664                 : 
    1665                 : static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
    1666                 :                                int extend, my_off_t page_pos, uchar *page_buff,
    1667                 :                                uint row_count)
    1668               0 : {
    1669               0 :   MARIA_SHARE *share= info->s;
    1670                 :   uchar *dir_entry;
    1671                 :   uint row;
    1672                 :   char llbuff[22], llbuff2[22];
    1673               0 :   ulonglong page= page_pos / share->block_size;
    1674               0 :   DBUG_ENTER("check_head_page");
    1675                 : 
    1676               0 :   dir_entry= page_buff+ share->block_size - PAGE_SUFFIX_SIZE;
    1677               0 :   for (row= 0 ; row < row_count ; row++)
    1678                 :   {
    1679                 :     uint pos, length, flag;
    1680               0 :     dir_entry-= DIR_ENTRY_SIZE;
    1681               0 :     pos= uint2korr(dir_entry);
    1682               0 :     if (!pos)
    1683               0 :       continue;
    1684               0 :     length= uint2korr(dir_entry+2);
    1685               0 :     if (length < share->base.min_block_length)
    1686                 :     {
    1687               0 :       _ma_check_print_error(param,
    1688                 :                             "Page %9s:  Row %3u is too short "
    1689                 :                             "(%d of min %d bytes)",
    1690                 :                             llstr(page, llbuff), row, length,
    1691                 :                             (uint) share->base.min_block_length);
    1692               0 :       DBUG_RETURN(1);
    1693                 :     }
    1694               0 :     flag= (uint) (uchar) page_buff[pos];
    1695               0 :     if (flag & ~(ROW_FLAG_ALL))
    1696               0 :       _ma_check_print_error(param,
    1697                 :                             "Page %9s: Row %3u has wrong flag: %u",
    1698                 :                             llstr(page, llbuff), row, flag);
    1699                 : 
    1700               0 :     DBUG_PRINT("info", ("rowid: %s  page: %lu  row: %u",
    1701                 :                         llstr(ma_recordpos(page, row), llbuff),
    1702                 :                         (ulong) page, row));
    1703               0 :     info->cur_row.trid= 0;
    1704               0 :     if (_ma_read_block_record2(info, record, page_buff+pos,
    1705                 :                                page_buff+pos+length))
    1706                 :     {
    1707               0 :       _ma_check_print_error(param,
    1708                 :                             "Page %9s:  Row %3d is crashed",
    1709                 :                             llstr(page, llbuff), row);
    1710               0 :       if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1711               0 :         DBUG_RETURN(1);
    1712                 :       continue;
    1713                 :     }
    1714               0 :     set_if_bigger(param->max_found_trid, info->cur_row.trid);
    1715               0 :     if (info->cur_row.trid > param->max_trid)
    1716               0 :       _ma_check_print_not_visible_error(param, info->cur_row.trid);
    1717                 : 
    1718               0 :     if (share->calc_checksum)
    1719                 :     {
    1720               0 :       ha_checksum checksum= (*share->calc_checksum)(info, record);
    1721               0 :       if (info->cur_row.checksum != (checksum & 255))
    1722               0 :         _ma_check_print_error(param, "Page %9s:  Row %3d has wrong checksum",
    1723                 :                               llstr(page, llbuff), row);
    1724               0 :       param->glob_crc+= checksum;
    1725                 :     }
    1726               0 :     if (info->cur_row.extents_count)
    1727                 :     {
    1728               0 :       uchar *extents= info->cur_row.extents;
    1729                 :       uint i;
    1730                 :       /* Check that bitmap has the right marker for the found extents */
    1731               0 :       for (i= 0 ; i < info->cur_row.extents_count ; i++)
    1732                 :       {
    1733                 :         pgcache_page_no_t extent_page;
    1734                 :         uint page_count, page_type;
    1735               0 :         extent_page= uint5korr(extents);
    1736               0 :         page_count=  uint2korr(extents+5) & ~START_EXTENT_BIT;
    1737               0 :         extents+=    ROW_EXTENT_SIZE;
    1738               0 :         page_type=   BLOB_PAGE;
    1739               0 :         if (page_count & TAIL_BIT)
    1740                 :         {
    1741               0 :           page_count= 1;
    1742               0 :           page_type= TAIL_PAGE;
    1743                 :         }
    1744                 :         /*
    1745                 :           TODO OPTIMIZE:
    1746                 :           Check the whole extent with one test and only do the loop if
    1747                 :           something is wrong (for exact error reporting)
    1748                 :         */
    1749               0 :         for ( ; page_count--; extent_page++)
    1750                 :         {
    1751                 :           uint bitmap_pattern;
    1752               0 :           if (_ma_check_if_right_bitmap_type(info, page_type, extent_page,
    1753                 :                                              &bitmap_pattern))
    1754                 :           {
    1755               0 :             _ma_check_print_error(param,
    1756                 :                                   "Page %9s:  Row: %3d has an extent with "
    1757                 :                                   "wrong information in bitmap:  "
    1758                 :                                   "Page %9s  Page_type: %d  Bitmap: %d",
    1759                 :                                   llstr(page, llbuff), row,
    1760                 :                                   llstr(extent_page, llbuff2),
    1761                 :                                   page_type, bitmap_pattern);
    1762               0 :             if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1763               0 :               DBUG_RETURN(1);
    1764                 :           }
    1765                 :         }
    1766                 :       }
    1767                 :     }
    1768               0 :     param->full_page_count+= info->cur_row.full_page_count;
    1769               0 :     param->tail_count+= info->cur_row.tail_count;
    1770               0 :     if (check_keys_in_record(param, info, extend,
    1771                 :                              ma_recordpos(page, row), record))
    1772               0 :       DBUG_RETURN(1);
    1773                 :   }
    1774               0 :   DBUG_RETURN(0);
    1775                 : }
    1776                 : 
    1777                 : 
    1778                 : /*
    1779                 :   Check if rows-in-block data file is consistent
    1780                 : */
    1781                 : 
    1782                 : static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
    1783                 :                               uchar *record)
    1784               0 : {
    1785               0 :   MARIA_SHARE *share= info->s;
    1786                 :   my_off_t pos;
    1787                 :   pgcache_page_no_t page;
    1788                 :   uchar *page_buff, *bitmap_buff, *data;
    1789                 :   char llbuff[22], llbuff2[22];
    1790               0 :   uint block_size= share->block_size;
    1791                 :   ha_rows full_page_count, tail_count;
    1792                 :   my_bool full_dir;
    1793                 :   uint offset_page, offset, free_count;
    1794                 : 
    1795               0 :   LINT_INIT(full_dir);
    1796                 : 
    1797               0 :   if (_ma_scan_init_block_record(info))
    1798                 :   {
    1799               0 :     _ma_check_print_error(param, "got error %d when initializing scan",
    1800                 :                           my_errno);
    1801               0 :     return 1;
    1802                 :   }
    1803               0 :   bitmap_buff= info->scan.bitmap_buff;
    1804               0 :   page_buff= info->scan.page_buff;
    1805               0 :   full_page_count= tail_count= 0;
    1806               0 :   param->full_page_count= param->tail_count= 0;
    1807               0 :   param->used= param->link_used= 0;
    1808               0 :   param->splits= share->state.state.data_file_length / block_size;
    1809                 : 
    1810               0 :   for (pos= 0, page= 0;
    1811               0 :        pos < share->state.state.data_file_length;
    1812               0 :        pos+= block_size, page++)
    1813                 :   {
    1814                 :     uint row_count, real_row_count, empty_space, page_type, bitmap_pattern;
    1815               0 :     LINT_INIT(row_count);
    1816               0 :     LINT_INIT(empty_space);
    1817                 : 
    1818               0 :     if (*_ma_killed_ptr(param))
    1819                 :     {
    1820               0 :       _ma_scan_end_block_record(info);
    1821               0 :       return -1;
    1822                 :     }
    1823               0 :     if ((page % share->bitmap.pages_covered) == 0)
    1824                 :     {
    1825                 :       /* Bitmap page */
    1826               0 :       if (pagecache_read(share->pagecache,
    1827                 :                          &info->s->bitmap.file,
    1828                 :                          page, 1,
    1829                 :                          bitmap_buff,
    1830                 :                          PAGECACHE_PLAIN_PAGE,
    1831                 :                          PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0)
    1832                 :       {
    1833               0 :         _ma_check_print_error(param,
    1834                 :                               "Page %9s:  Got error: %d when reading datafile",
    1835                 :                               llstr(page, llbuff), my_errno);
    1836               0 :         goto err;
    1837                 :       }
    1838               0 :       param->used+= block_size;
    1839               0 :       param->link_used+= block_size;
    1840               0 :       continue;
    1841                 :     }
    1842                 :     /* Skip pages marked as empty in bitmap */
    1843               0 :     offset_page= (uint) ((page % share->bitmap.pages_covered) -1) * 3;
    1844               0 :     offset= offset_page & 7;
    1845               0 :     data= bitmap_buff + offset_page / 8;
    1846               0 :     bitmap_pattern= uint2korr(data);
    1847               0 :     if (!((bitmap_pattern >> offset) & 7))
    1848                 :     {
    1849               0 :       param->empty+= block_size;
    1850               0 :       param->del_blocks++;
    1851               0 :       continue;
    1852                 :     }
    1853                 : 
    1854               0 :     if (pagecache_read(share->pagecache,
    1855                 :                        &info->dfile,
    1856                 :                        page, 1,
    1857                 :                        page_buff,
    1858                 :                        share->page_type,
    1859                 :                        PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0)
    1860                 :     {
    1861               0 :       _ma_check_print_error(param,
    1862                 :                             "Page %9s:  Got error: %d when reading datafile",
    1863                 :                             llstr(page, llbuff), my_errno);
    1864               0 :       goto err;
    1865                 :     }
    1866               0 :     page_type= page_buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK;
    1867               0 :     if (page_type == UNALLOCATED_PAGE || page_type >= MAX_PAGE_TYPE)
    1868                 :     {
    1869               0 :       _ma_check_print_error(param,
    1870                 :                             "Page: %9s  Found wrong page type %d",
    1871                 :                             llstr(page, llbuff), page_type);
    1872               0 :       if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1873                 :         goto err;
    1874                 :       continue;
    1875                 :     }
    1876               0 :     switch ((enum en_page_type) page_type) {
    1877                 :     case UNALLOCATED_PAGE:
    1878                 :     case MAX_PAGE_TYPE:
    1879                 :     default:
    1880               0 :       DBUG_ASSERT(0);                           /* Impossible */
    1881                 :       break;
    1882                 :     case HEAD_PAGE:
    1883               0 :       row_count= page_buff[DIR_COUNT_OFFSET];
    1884               0 :       empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET);
    1885               0 :       param->used+= block_size - empty_space;
    1886               0 :       param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE +
    1887                 :                           row_count * DIR_ENTRY_SIZE);
    1888               0 :       if (empty_space < share->bitmap.sizes[3])
    1889               0 :         param->lost+= empty_space;
    1890               0 :       if (check_page_layout(param, info, pos, page_buff, row_count,
    1891                 :                             empty_space, &real_row_count, &free_count))
    1892               0 :         goto err;
    1893               0 :       full_dir= (row_count == MAX_ROWS_PER_PAGE &&
    1894                 :                  page_buff[DIR_FREE_OFFSET] == END_OF_DIR_FREE_LIST);
    1895               0 :       break;
    1896                 :     case TAIL_PAGE:
    1897               0 :       row_count= page_buff[DIR_COUNT_OFFSET];
    1898               0 :       empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET);
    1899               0 :       param->used+= block_size - empty_space;
    1900               0 :       param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE +
    1901                 :                           row_count * DIR_ENTRY_SIZE);
    1902               0 :       if (empty_space < share->bitmap.sizes[6])
    1903               0 :         param->lost+= empty_space;
    1904               0 :       if (check_page_layout(param, info, pos, page_buff, row_count,
    1905                 :                             empty_space, &real_row_count, &free_count))
    1906               0 :         goto err;
    1907               0 :       full_dir= (row_count - free_count >= MAX_ROWS_PER_PAGE -
    1908                 :                  share->base.blobs);
    1909               0 :       break;
    1910                 :     case BLOB_PAGE:
    1911               0 :       full_page_count++;
    1912               0 :       full_dir= 0;
    1913               0 :       empty_space= block_size;                  /* for error reporting */
    1914               0 :       param->link_used+= (LSN_SIZE + PAGE_TYPE_SIZE);
    1915               0 :       param->used+= block_size;
    1916                 :       break;
    1917                 :     }
    1918               0 :     if (_ma_check_bitmap_data(info, page_type, page,
    1919                 :                               full_dir ? 0 : empty_space,
    1920                 :                               &bitmap_pattern))
    1921                 :     {
    1922               0 :       if (bitmap_pattern == ~(uint) 0)
    1923               0 :         _ma_check_print_error(param,
    1924                 :                               "Page %9s: Wrong bitmap for data on page",
    1925                 :                               llstr(page, llbuff));
    1926                 :       else
    1927               0 :         _ma_check_print_error(param,
    1928                 :                               "Page %9s:  Wrong data in bitmap.  Page_type: "
    1929                 :                               "%d  empty_space: %u  Bitmap-bits: %d",
    1930                 :                               llstr(page, llbuff), page_type,
    1931                 :                               empty_space, bitmap_pattern);
    1932               0 :       if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
    1933                 :         goto err;
    1934                 :     }
    1935               0 :     if ((enum en_page_type) page_type == BLOB_PAGE)
    1936               0 :       continue;
    1937               0 :     param->empty+= empty_space;
    1938               0 :     if ((enum en_page_type) page_type == TAIL_PAGE)
    1939                 :     {
    1940               0 :       tail_count+= real_row_count;
    1941               0 :       continue;
    1942                 :     }
    1943               0 :     if (check_head_page(param, info, record, extend, pos, page_buff,
    1944                 :                         row_count))
    1945               0 :       goto err;
    1946                 :   }
    1947                 : 
    1948                 :   /* Verify that rest of bitmap is zero */
    1949                 : 
    1950               0 :   if (page % share->bitmap.pages_covered)
    1951                 :   {
    1952                 :     /* Not at end of bitmap */
    1953                 :     uint bitmap_pattern;
    1954               0 :     offset_page= (uint) ((page % share->bitmap.pages_covered) -1) * 3;
    1955               0 :     offset= offset_page & 7;
    1956               0 :     data= bitmap_buff + offset_page / 8;
    1957               0 :     bitmap_pattern= uint2korr(data);
    1958               0 :     if (((bitmap_pattern >> offset)) ||
    1959                 :         (data + 2 < bitmap_buff + share->bitmap.total_size &&
    1960                 :          _ma_check_if_zero(data+2, bitmap_buff + share->bitmap.total_size -
    1961                 :                            data - 2)))
    1962                 :     {
    1963                 :       ulonglong bitmap_page;
    1964               0 :       bitmap_page= page / share->bitmap.pages_covered;
    1965               0 :       bitmap_page*= share->bitmap.pages_covered;
    1966                 : 
    1967               0 :       _ma_check_print_error(param,
    1968                 :                             "Bitmap at page %s has pages reserved outside of "
    1969                 :                             "data file length",
    1970                 :                             llstr(bitmap_page, llbuff));
    1971               0 :       DBUG_EXECUTE("bitmap", _ma_print_bitmap(&share->bitmap, bitmap_buff,
    1972                 :                                               bitmap_page););
    1973                 :     }
    1974                 :   }
    1975                 : 
    1976               0 :   _ma_scan_end_block_record(info);
    1977                 : 
    1978               0 :   if (full_page_count != param->full_page_count)
    1979               0 :     _ma_check_print_error(param, "Full page count read through records was %s "
    1980                 :                           "but we found %s pages while scanning table",
    1981                 :                           llstr(param->full_page_count, llbuff),
    1982                 :                           llstr(full_page_count, llbuff2));
    1983               0 :   if (tail_count != param->tail_count)
    1984               0 :     _ma_check_print_error(param, "Tail count read through records was %s but "
    1985                 :                           "we found %s tails while scanning table",
    1986                 :                           llstr(param->tail_count, llbuff),
    1987                 :                           llstr(tail_count, llbuff2));
    1988                 : 
    1989               0 :   return param->error_printed != 0;
    1990                 : 
    1991               0 : err:
    1992               0 :   _ma_scan_end_block_record(info);
    1993               0 :   return 1;
    1994                 : }
    1995                 : 
    1996                 : 
    1997                 : /* Check that record-link is ok */
    1998                 : 
    1999                 : int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
    2000               0 : {
    2001               0 :   MARIA_SHARE *share= info->s;
    2002                 :   int   error;
    2003                 :   uchar *record;
    2004                 :   char llbuff[22],llbuff2[22],llbuff3[22];
    2005               0 :   DBUG_ENTER("maria_chk_data_link");
    2006                 : 
    2007               0 :   if (!(param->testflag & T_SILENT))
    2008                 :   {
    2009               0 :     if (extend)
    2010               0 :       puts("- check records and index references");
    2011                 :     else
    2012               0 :       puts("- check record links");
    2013                 :   }
    2014                 : 
    2015               0 :   if (!(record= (uchar*) my_malloc(share->base.default_rec_buff_size, MYF(0))))
    2016                 :   {
    2017               0 :     _ma_check_print_error(param,"Not enough memory for record");
    2018               0 :     DBUG_RETURN(-1);
    2019                 :   }
    2020               0 :   param->records= param->del_blocks= 0;
    2021               0 :   param->used= param->link_used= param->splits= param->del_length= 0;
    2022               0 :   param->lost= 0;
    2023               0 :   param->tmp_record_checksum= param->glob_crc= 0;
    2024               0 :   param->err_count= 0;
    2025                 : 
    2026               0 :   error= 0;
    2027               0 :   param->empty= share->pack.header_length;
    2028                 : 
    2029               0 :   bzero((char*) param->tmp_key_crc,
    2030                 :         share->base.keys * sizeof(param->tmp_key_crc[0]));
    2031                 : 
    2032               0 :   switch (share->data_file_type) {
    2033                 :   case BLOCK_RECORD:
    2034               0 :     error= check_block_record(param, info, extend, record);
    2035               0 :     break;
    2036                 :   case STATIC_RECORD:
    2037               0 :     error= check_static_record(param, info, extend, record);
    2038               0 :     break;
    2039                 :   case DYNAMIC_RECORD:
    2040               0 :     error= check_dynamic_record(param, info, extend, record);
    2041               0 :     break;
    2042                 :   case COMPRESSED_RECORD:
    2043               0 :     error= check_compressed_record(param, info, extend, record);
    2044                 :     break;
    2045                 :   } /* switch */
    2046                 : 
    2047               0 :   if (error)
    2048               0 :     goto err;
    2049                 : 
    2050               0 :   if (param->testflag & T_WRITE_LOOP)
    2051                 :   {
    2052               0 :     VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
    2053                 :   }
    2054               0 :   if (param->records != share->state.state.records)
    2055                 :   {
    2056               0 :     _ma_check_print_error(param,
    2057                 :                           "Record-count is not ok; found %-10s  Should be: %s",
    2058                 :                           llstr(param->records,llbuff),
    2059                 :                           llstr(share->state.state.records,llbuff2));
    2060               0 :     error=1;
    2061                 :   }
    2062               0 :   else if (param->record_checksum &&
    2063                 :            param->record_checksum != param->tmp_record_checksum)
    2064                 :   {
    2065               0 :     _ma_check_print_error(param,
    2066                 :                           "Key pointers and record positions doesn't match");
    2067               0 :     error=1;
    2068                 :   }
    2069               0 :   else if (param->glob_crc != share->state.state.checksum &&
    2070                 :            (share->options &
    2071                 :             (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
    2072                 :   {
    2073               0 :     _ma_check_print_warning(param,
    2074                 :                             "Record checksum is not the same as checksum "
    2075                 :                             "stored in the index file");
    2076               0 :     error=1;
    2077                 :   }
    2078               0 :   else if (!extend)
    2079                 :   {
    2080                 :     uint key;
    2081               0 :     for (key=0 ; key < share->base.keys;  key++)
    2082                 :     {
    2083               0 :       if (param->tmp_key_crc[key] != param->key_crc[key] &&
    2084                 :           !(share->keyinfo[key].flag &
    2085                 :             (HA_FULLTEXT | HA_SPATIAL | HA_RTREE_INDEX)))
    2086                 :       {
    2087               0 :         _ma_check_print_error(param,"Checksum for key: %2d doesn't match "
    2088                 :                               "checksum for records",
    2089                 :                               key+1);
    2090               0 :         error=1;
    2091                 :       }
    2092                 :     }
    2093                 :   }
    2094                 : 
    2095               0 :   if (param->del_length != share->state.state.empty)
    2096                 :   {
    2097               0 :     _ma_check_print_warning(param,
    2098                 :                             "Found %s deleted space.   Should be %s",
    2099                 :                             llstr(param->del_length,llbuff2),
    2100                 :                             llstr(share->state.state.empty,llbuff));
    2101                 :   }
    2102                 :   /* Skip following checks for BLOCK RECORD as they don't make any sence */
    2103               0 :   if (share->data_file_type != BLOCK_RECORD)
    2104                 :   {
    2105               0 :     if (param->used + param->empty + param->del_length !=
    2106                 :         share->state.state.data_file_length)
    2107                 :     {
    2108               0 :       _ma_check_print_warning(param,
    2109                 :                               "Found %s record data and %s unused data and %s "
    2110                 :                               "deleted data",
    2111                 :                               llstr(param->used, llbuff),
    2112                 :                               llstr(param->empty,llbuff2),
    2113                 :                               llstr(param->del_length,llbuff3));
    2114               0 :       _ma_check_print_warning(param,
    2115                 :                               "Total %s   Should be: %s",
    2116                 :                               llstr((param->used+param->empty +
    2117                 :                                      param->del_length), llbuff),
    2118                 :                               llstr(share->state.state.data_file_length,
    2119                 :                                     llbuff2));
    2120                 :     }
    2121               0 :     if (param->del_blocks != share->state.state.del)
    2122                 :     {
    2123               0 :       _ma_check_print_warning(param,
    2124                 :                               "Found %10s deleted blocks.  Should be: %s",
    2125                 :                               llstr(param->del_blocks,llbuff),
    2126                 :                               llstr(share->state.state.del,llbuff2));
    2127                 :     }
    2128               0 :     if (param->splits != share->state.split)
    2129                 :     {
    2130               0 :       _ma_check_print_warning(param,
    2131                 :                               "Found %10s parts.  Should be: %s",
    2132                 :                               llstr(param->splits, llbuff),
    2133                 :                               llstr(share->state.split,llbuff2));
    2134                 :     }
    2135                 :   }
    2136               0 :   if (param->testflag & T_INFO)
    2137                 :   {
    2138               0 :     if (param->warning_printed || param->error_printed)
    2139               0 :       puts("");
    2140               0 :     if (param->used != 0 && ! param->error_printed)
    2141                 :     {
    2142               0 :       if (param->records)
    2143                 :       {
    2144               0 :         printf("Records:%18s    M.recordlength:%9lu   Packed:%14.0f%%\n",
    2145                 :                llstr(param->records,llbuff),
    2146                 :                (long)((param->used - param->link_used)/param->records),
    2147                 :                (share->base.blobs ? 0.0 :
    2148                 :                 (ulonglong2double((ulonglong) share->base.reclength *
    2149                 :                                   param->records)-
    2150                 :                  my_off_t2double(param->used))/
    2151                 :                 ulonglong2double((ulonglong) share->base.reclength *
    2152                 :                                  param->records)*100.0));
    2153               0 :         printf("Recordspace used:%9.0f%%   Empty space:%12d%%  "
    2154                 :                "Blocks/Record: %6.2f\n",
    2155                 :                (ulonglong2double(param->used - param->link_used)/
    2156                 :                 ulonglong2double(param->used-param->link_used+param->empty) *
    2157                 :                 100.0),
    2158                 :                (!param->records ? 100 :
    2159                 :                 (int) (ulonglong2double(param->del_length+param->empty)/
    2160                 :                        my_off_t2double(param->used)*100.0)),
    2161                 :                ulonglong2double(param->splits - param->del_blocks) /
    2162                 :                param->records);
    2163                 :       }
    2164                 :       else
    2165               0 :         printf("Records:%18s\n", "0");
    2166                 :     }
    2167               0 :     printf("Record blocks:%12s    Delete blocks:%10s\n",
    2168                 :            llstr(param->splits - param->del_blocks, llbuff),
    2169                 :            llstr(param->del_blocks, llbuff2));
    2170               0 :     printf("Record data:  %12s    Deleted data: %10s\n",
    2171                 :            llstr(param->used - param->link_used,llbuff),
    2172                 :            llstr(param->del_length, llbuff2));
    2173               0 :     printf("Empty space:  %12s    Linkdata:     %10s\n",
    2174                 :            llstr(param->empty, llbuff),llstr(param->link_used, llbuff2));
    2175               0 :     if (param->lost)
    2176               0 :       printf("Lost space:   %12s", llstr(param->lost, llbuff));
    2177               0 :     if (param->max_found_trid)
    2178                 :     {
    2179               0 :       printf("Max trans. id: %11s\n",
    2180                 :              llstr(param->max_found_trid, llbuff));
    2181                 :     }
    2182                 :   }
    2183               0 :   my_free(record,MYF(0));
    2184               0 :   DBUG_RETURN (error);
    2185                 : 
    2186               0 : err:
    2187               0 :   my_free(record,MYF(0));
    2188               0 :   param->testflag|=T_RETRY_WITHOUT_QUICK;
    2189               0 :   DBUG_RETURN(1);
    2190                 : } /* maria_chk_data_link */
    2191                 : 
    2192                 : 
    2193                 : /**
    2194                 :   Prepares a table for a repair or index sort: flushes pages, records durably
    2195                 :   in the table that it is undergoing the operation (if that op crashes, that
    2196                 :   info will serve for Recovery and the user).
    2197                 : 
    2198                 :   If we start overwriting the index file, and crash then, old REDOs will
    2199                 :   be tried and fail. To prevent that, we bump skip_redo_lsn, and thus we have
    2200                 :   to flush and sync pages so that old REDOs can be skipped.
    2201                 :   If this is not a bulk insert, which Recovery can handle gracefully (by
    2202                 :   truncating files, see UNDO_BULK_INSERT) we also mark the table
    2203                 :   crashed-on-repair, so that user knows it has to re-repair. If bulk insert we
    2204                 :   shouldn't mark it crashed-on-repair, because if we did this, the UNDO phase
    2205                 :   would skip the table (UNDO_BULK_INSERT would not be applied),
    2206                 :   and maria_chk would not improve that.
    2207                 :   If this is an OPTIMIZE which merely sorts index, we need to do the same
    2208                 :   too: old REDOs should not apply to the new index file.
    2209                 :   Only the flush is needed when in maria_chk which is not crash-safe.
    2210                 : 
    2211                 :   @param  info             table
    2212                 :   @param  param            repair parameters
    2213                 :   @param  discard_index    if index pages can be thrown away
    2214                 : */
    2215                 : 
    2216                 : static my_bool protect_against_repair_crash(MARIA_HA *info,
    2217                 :                                             const HA_CHECK *param,
    2218                 :                                             my_bool discard_index)
    2219               0 : {
    2220               0 :   MARIA_SHARE *share= info->s;
    2221                 : 
    2222                 :   /*
    2223                 :     There are other than recovery-related reasons to do the writes below:
    2224                 :     - the physical size of the data file is sometimes used during repair: we
    2225                 :     need to flush to have it exact
    2226                 :     - we flush the state because maria_open(HA_OPEN_COPY) will want to read
    2227                 :     it from disk.
    2228                 :   */
    2229               0 :   if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
    2230                 :                             FLUSH_FORCE_WRITE,
    2231                 :                             discard_index ? FLUSH_IGNORE_CHANGED :
    2232                 :                             FLUSH_FORCE_WRITE) ||
    2233                 :       (share->changed &&
    2234                 :        _ma_state_info_write(share,
    2235                 :                             MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
    2236                 :                             MA_STATE_INFO_WRITE_FULL_INFO |
    2237                 :                             MA_STATE_INFO_WRITE_LOCK)))
    2238               0 :     return TRUE;
    2239                 :   /* In maria_chk this is not needed: */
    2240               0 :   if (maria_multi_threaded && share->base.born_transactional)
    2241                 :   {
    2242               0 :     if ((param->testflag & T_NO_CREATE_RENAME_LSN) == 0)
    2243                 :     {
    2244                 :       /* this can be true only for a transactional table */
    2245               0 :       maria_mark_crashed_on_repair(info);
    2246               0 :       if (_ma_state_info_write(share,
    2247                 :                                MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
    2248                 :                                MA_STATE_INFO_WRITE_LOCK))
    2249               0 :         return TRUE;
    2250                 :     }
    2251               0 :     if (translog_status == TRANSLOG_OK &&
    2252                 :         _ma_update_state_lsns(share, translog_get_horizon(),
    2253                 :                               share->state.create_trid, FALSE, FALSE))
    2254               0 :       return TRUE;
    2255               0 :     if (_ma_sync_table_files(info))
    2256               0 :       return TRUE;
    2257                 :   }
    2258               0 :   return FALSE;
    2259                 : }
    2260                 : 
    2261                 : 
    2262                 : /**
    2263                 :    @brief Initialize variables for repair
    2264                 : */
    2265                 : 
    2266                 : static int initialize_variables_for_repair(HA_CHECK *param,
    2267                 :                                            MARIA_SORT_INFO *sort_info,
    2268                 :                                            MARIA_SORT_PARAM *sort_param,
    2269                 :                                            MARIA_HA *info,
    2270                 :                                            my_bool rep_quick)
    2271               0 : {
    2272               0 :   MARIA_SHARE *share= info->s;
    2273                 : 
    2274                 :   /* Repair code relies on share->state.state so we have to update it here */
    2275               0 :   if (share->lock.update_status)
    2276               0 :     (*share->lock.update_status)(info);
    2277                 : 
    2278               0 :   bzero((char*) sort_info,  sizeof(*sort_info));
    2279               0 :   bzero((char*) sort_param, sizeof(*sort_param));
    2280                 : 
    2281               0 :   param->testflag|= T_REP;                     /* for easy checking */
    2282               0 :   if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
    2283               0 :     param->testflag|= T_CALC_CHECKSUM;
    2284               0 :   param->glob_crc= 0;
    2285               0 :   if (rep_quick)
    2286               0 :     param->testflag|= T_QUICK;
    2287                 :   else
    2288               0 :     param->testflag&= ~T_QUICK;
    2289               0 :   param->org_key_map= share->state.key_map;
    2290                 : 
    2291               0 :   sort_param->sort_info= sort_info;
    2292               0 :   sort_param->fix_datafile= ! rep_quick;
    2293               0 :   sort_param->calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
    2294               0 :   sort_info->info= sort_info->new_info= info;
    2295               0 :   sort_info->param= param;
    2296               0 :   set_data_file_type(sort_info, info->s);
    2297               0 :   sort_info->org_data_file_type= share->data_file_type;
    2298                 : 
    2299               0 :   bzero(&info->rec_cache, sizeof(info->rec_cache));
    2300               0 :   info->rec_cache.file= info->dfile.file;
    2301               0 :   info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
    2302                 : 
    2303               0 :   if (protect_against_repair_crash(info, param, !test(param->testflag &
    2304                 :                                                       T_CREATE_MISSING_KEYS)))
    2305               0 :     return 1;
    2306                 : 
    2307                 :   /* calculate max_records */
    2308               0 :   sort_info->filelength= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
    2309               0 :   if ((param->testflag & T_CREATE_MISSING_KEYS) ||
    2310                 :       sort_info->org_data_file_type == COMPRESSED_RECORD)
    2311               0 :     sort_info->max_records= share->state.state.records;
    2312                 :   else
    2313                 :   {
    2314                 :     ulong rec_length;
    2315               0 :     rec_length= max(share->base.min_pack_length,
    2316                 :                     share->base.min_block_length);
    2317               0 :     sort_info->max_records= (ha_rows) (sort_info->filelength / rec_length);
    2318                 :   }
    2319                 : 
    2320                 :   /* Set up transaction handler so that we can see all rows */
    2321               0 :   if (!ma_control_file_inited())
    2322               0 :     param->max_trid= 0;                 /* Give warning for first trid found */
    2323                 :   else
    2324               0 :     param->max_trid= max_trid_in_system();
    2325                 : 
    2326               0 :   maria_ignore_trids(info);
    2327                 :   /* Don't write transid's during repair */
    2328               0 :   maria_versioning(info, 0);
    2329               0 :   return 0;
    2330                 : }
    2331                 : 
    2332                 : 
    2333                 : /**
    2334                 :   @brief Drop all indexes
    2335                 : 
    2336                 :   @param[in]    param           check parameters
    2337                 :   @param[in]    info            MARIA_HA handle
    2338                 :   @param[in]    force           if to force drop all indexes
    2339                 : 
    2340                 :   @return       status
    2341                 :     @retval     0               OK
    2342                 :     @retval     != 0            Error
    2343                 : 
    2344                 :   @note
    2345                 :     Once allocated, index blocks remain part of the key file forever.
    2346                 :     When indexes are disabled, no block is freed. When enabling indexes,
    2347                 :     no block is freed either. The new indexes are create from new
    2348                 :     blocks. (Bug #4692)
    2349                 : 
    2350                 :     Before recreating formerly disabled indexes, the unused blocks
    2351                 :     must be freed. There are two options to do this:
    2352                 :     - Follow the tree of disabled indexes, add all blocks to the
    2353                 :       deleted blocks chain. Would require a lot of random I/O.
    2354                 :     - Drop all blocks by clearing all index root pointers and all
    2355                 :       delete chain pointers and resetting key_file_length to the end
    2356                 :       of the index file header. This requires to recreate all indexes,
    2357                 :       even those that may still be intact.
    2358                 :     The second method is probably faster in most cases.
    2359                 : 
    2360                 :     When disabling indexes, MySQL disables either all indexes or all
    2361                 :     non-unique indexes. When MySQL [re-]enables disabled indexes
    2362                 :     (T_CREATE_MISSING_KEYS), then we either have "lost" blocks in the
    2363                 :     index file, or there are no non-unique indexes. In the latter case,
    2364                 :     maria_repair*() would not be called as there would be no disabled
    2365                 :     indexes.
    2366                 : 
    2367                 :     If there would be more unique indexes than disabled (non-unique)
    2368                 :     indexes, we could do the first method. But this is not implemented
    2369                 :     yet. By now we drop and recreate all indexes when repair is called.
    2370                 : 
    2371                 :     However, there is an exception. Sometimes MySQL disables non-unique
    2372                 :     indexes when the table is empty (e.g. when copying a table in
    2373                 :     mysql_alter_table()). When enabling the non-unique indexes, they
    2374                 :     are still empty. So there is no index block that can be lost. This
    2375                 :     optimization is implemented in this function.
    2376                 : 
    2377                 :     Note that in normal repair (T_CREATE_MISSING_KEYS not set) we
    2378                 :     recreate all enabled indexes unconditonally. We do not change the
    2379                 :     key_map. Otherwise we invert the key map temporarily (outside of
    2380                 :     this function) and recreate the then "seemingly" enabled indexes.
    2381                 :     When we cannot use the optimization, and drop all indexes, we
    2382                 :     pretend that all indexes were disabled. By the inversion, we will
    2383                 :     then recrate all indexes.
    2384                 : */
    2385                 : 
    2386                 : static int maria_drop_all_indexes(HA_CHECK *param, MARIA_HA *info,
    2387                 :                                   my_bool force)
    2388               0 : {
    2389               0 :   MARIA_SHARE *share= info->s;
    2390               0 :   MARIA_STATE_INFO *state= &share->state;
    2391                 :   uint i;
    2392               0 :   DBUG_ENTER("maria_drop_all_indexes");
    2393                 : 
    2394                 :   /*
    2395                 :     If any of the disabled indexes has a key block assigned, we must
    2396                 :     drop and recreate all indexes to avoid losing index blocks.
    2397                 : 
    2398                 :     If we want to recreate disabled indexes only _and_ all of these
    2399                 :     indexes are empty, we don't need to recreate the existing indexes.
    2400                 :   */
    2401               0 :   if (!force && (param->testflag & T_CREATE_MISSING_KEYS))
    2402                 :   {
    2403               0 :     DBUG_PRINT("repair", ("creating missing indexes"));
    2404               0 :     for (i= 0; i < share->base.keys; i++)
    2405                 :     {
    2406               0 :       DBUG_PRINT("repair", ("index #: %u  key_root: 0x%lx  active: %d",
    2407                 :                             i, (long) state->key_root[i],
    2408                 :                             maria_is_key_active(state->key_map, i)));
    2409               0 :       if ((state->key_root[i] != HA_OFFSET_ERROR) &&
    2410                 :           !maria_is_key_active(state->key_map, i))
    2411                 :       {
    2412                 :         /*
    2413                 :           This index has at least one key block and it is disabled.
    2414                 :           We would lose its block(s) if would just recreate it.
    2415                 :           So we need to drop and recreate all indexes.
    2416                 :         */
    2417               0 :         DBUG_PRINT("repair", ("nonempty and disabled: recreate all"));
    2418               0 :         break;
    2419                 :       }
    2420                 :     }
    2421               0 :     if (i >= share->base.keys)
    2422               0 :       goto end;
    2423                 : 
    2424                 :     /*
    2425                 :       We do now drop all indexes and declare them disabled. With the
    2426                 :       T_CREATE_MISSING_KEYS flag, maria_repair*() will recreate all
    2427                 :       disabled indexes and enable them.
    2428                 :     */
    2429               0 :     maria_clear_all_keys_active(state->key_map);
    2430               0 :     DBUG_PRINT("repair", ("declared all indexes disabled"));
    2431                 :   }
    2432                 : 
    2433                 :   /* Clear index root block pointers. */
    2434               0 :   for (i= 0; i < share->base.keys; i++)
    2435               0 :     state->key_root[i]= HA_OFFSET_ERROR;
    2436                 : 
    2437                 :   /* Drop the delete chain. */
    2438               0 :   share->state.key_del=  HA_OFFSET_ERROR;
    2439                 : 
    2440                 :   /* Reset index file length to end of index file header. */
    2441               0 :   share->state.state.key_file_length= share->base.keystart;
    2442                 : 
    2443               0 : end:
    2444               0 :   DBUG_RETURN(0);
    2445                 : }
    2446                 : 
    2447                 : 
    2448                 : /*
    2449                 :   Recover old table by reading each record and writing all keys
    2450                 : 
    2451                 :   NOTES
    2452                 :     Save new datafile-name in temp_filename.
    2453                 :     We overwrite the index file as we go (writekeys() for example), so if we
    2454                 :     crash during this the table is unusable and user (or Recovery in the
    2455                 :     future) must repeat the REPAIR/OPTIMIZE operation. We could use a
    2456                 :     temporary index file in the future (drawback: more disk space).
    2457                 : 
    2458                 :   IMPLEMENTATION (for hard repair with block format)
    2459                 :    - Create new, unrelated MARIA_HA of the table
    2460                 :    - Create new datafile and associate it with new handler
    2461                 :    - Reset all statistic information in new handler
    2462                 :    - Copy all data to new handler with normal write operations
    2463                 :    - Move state of new handler to old handler
    2464                 :    - Close new handler
    2465                 :    - Close data file in old handler
    2466                 :    - Rename old data file to new data file.
    2467                 :    - Reopen data file in old handler
    2468                 : */
    2469                 : 
    2470                 : int maria_repair(HA_CHECK *param, register MARIA_HA *info,
    2471                 :                  char *name, my_bool rep_quick)
    2472               0 : {
    2473                 :   int error, got_error;
    2474                 :   ha_rows start_records,new_header_length;
    2475                 :   my_off_t del;
    2476                 :   File new_file;
    2477               0 :   MARIA_SHARE *share= info->s;
    2478                 :   char llbuff[22],llbuff2[22];
    2479                 :   MARIA_SORT_INFO sort_info;
    2480                 :   MARIA_SORT_PARAM sort_param;
    2481               0 :   my_bool block_record, scan_inited= 0,
    2482               0 :     reenable_logging= share->now_transactional;
    2483               0 :   enum data_file_type org_data_file_type= share->data_file_type;
    2484                 :   myf sync_dir= ((share->now_transactional && !share->temporary) ?
    2485               0 :                  MY_SYNC_DIR : 0);
    2486               0 :   DBUG_ENTER("maria_repair");
    2487                 : 
    2488               0 :   got_error= 1;
    2489               0 :   new_file= -1;
    2490               0 :   start_records= share->state.state.records;
    2491               0 :   if (!(param->testflag & T_SILENT))
    2492                 :   {
    2493               0 :     printf("- recovering (with keycache) MARIA-table '%s'\n",name);
    2494               0 :     printf("Data records: %s\n", llstr(start_records, llbuff));
    2495                 :   }
    2496                 : 
    2497               0 :   if (initialize_variables_for_repair(param, &sort_info, &sort_param, info,
    2498                 :                                       rep_quick))
    2499               0 :     goto err;
    2500                 : 
    2501               0 :   if (reenable_logging)
    2502               0 :     _ma_tmp_disable_logging_for_table(info, 0);
    2503                 : 
    2504               0 :   sort_param.current_filepos= sort_param.filepos= new_header_length=
    2505                 :     ((param->testflag & T_UNPACK) ? 0L : share->pack.header_length);
    2506                 : 
    2507               0 :   if (!rep_quick)
    2508                 :   {
    2509                 :     /* Get real path for data file */
    2510               0 :     if ((new_file= my_create(fn_format(param->temp_filename,
    2511                 :                                        share->data_file_name.str, "",
    2512                 :                                        DATA_TMP_EXT, 2+4),
    2513                 :                              0,param->tmpfile_createflag,
    2514                 :                              MYF(0))) < 0)
    2515                 :     {
    2516               0 :       _ma_check_print_error(param,"Can't create new tempfile: '%s'",
    2517                 :                            param->temp_filename);
    2518               0 :       goto err;
    2519                 :     }
    2520               0 :     if (new_header_length &&
    2521                 :         maria_filecopy(param, new_file, info->dfile.file, 0L,
    2522                 :                        new_header_length, "datafile-header"))
    2523               0 :       goto err;
    2524               0 :     share->state.dellink= HA_OFFSET_ERROR;
    2525               0 :     info->rec_cache.file= new_file;             /* For sort_delete_record */
    2526               0 :     if (share->data_file_type == BLOCK_RECORD ||
    2527                 :         (param->testflag & T_UNPACK))
    2528                 :     {
    2529               0 :       if (create_new_data_handle(&sort_param, new_file))
    2530               0 :         goto err;
    2531               0 :       sort_info.new_info->rec_cache.file= new_file;
    2532                 :     }
    2533                 :   }
    2534                 : 
    2535               0 :   block_record= sort_info.new_info->s->data_file_type == BLOCK_RECORD;
    2536                 : 
    2537               0 :   if (org_data_file_type != BLOCK_RECORD)
    2538                 :   {
    2539                 :     /* We need a read buffer to read rows in big blocks */
    2540               0 :     if (init_io_cache(&param->read_cache, info->dfile.file,
    2541                 :                       (uint) param->read_buffer_length,
    2542                 :                       READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)))
    2543               0 :       goto err;
    2544                 :   }
    2545               0 :   if (sort_info.new_info->s->data_file_type != BLOCK_RECORD)
    2546                 :   {
    2547                 :     /* When writing to not block records, we need a write buffer */
    2548               0 :     if (!rep_quick)
    2549                 :     {
    2550               0 :       if (init_io_cache(&sort_info.new_info->rec_cache, new_file,
    2551                 :                         (uint) param->write_buffer_length,
    2552                 :                         WRITE_CACHE, new_header_length, 1,
    2553                 :                         MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw))
    2554               0 :         goto err;
    2555               0 :       sort_info.new_info->opt_flag|=WRITE_CACHE_USED;
    2556                 :     }
    2557                 :   }
    2558               0 :   else if (block_record)
    2559                 :   {
    2560               0 :     scan_inited= 1;
    2561               0 :     if (maria_scan_init(sort_info.info))
    2562               0 :       goto err;
    2563                 :   }
    2564                 : 
    2565               0 :   if (!(sort_param.record=
    2566                 :         (uchar *) my_malloc((uint)
    2567                 :                             share->base.default_rec_buff_size, MYF(0))) ||
    2568                 :       _ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
    2569                 :                        share->base.default_rec_buff_size))
    2570                 :   {
    2571               0 :     _ma_check_print_error(param, "Not enough memory for extra record");
    2572               0 :     goto err;
    2573                 :   }
    2574                 : 
    2575               0 :   sort_param.read_cache=param->read_cache;
    2576               0 :   sort_param.pos=sort_param.max_pos=share->pack.header_length;
    2577               0 :   param->read_cache.end_of_file= sort_info.filelength;
    2578               0 :   sort_param.master=1;
    2579               0 :   sort_info.max_records= ~(ha_rows) 0;
    2580                 : 
    2581               0 :   del= share->state.state.del;
    2582               0 :   share->state.state.records= share->state.state.del= share->state.split= 0;
    2583               0 :   share->state.state.empty= 0;
    2584                 : 
    2585               0 :   if (param->testflag & T_CREATE_MISSING_KEYS)
    2586               0 :     maria_set_all_keys_active(share->state.key_map, share->base.keys);
    2587               0 :   maria_drop_all_indexes(param, info, TRUE);
    2588                 : 
    2589               0 :   maria_lock_memory(param);                     /* Everything is alloced */
    2590                 : 
    2591                 :   /* Re-create all keys, which are set in key_map. */
    2592               0 :   while (!(error=sort_get_next_record(&sort_param)))
    2593                 :   {
    2594               0 :     if (block_record && _ma_sort_write_record(&sort_param))
    2595               0 :       goto err;
    2596                 : 
    2597               0 :     if (writekeys(&sort_param))
    2598                 :     {
    2599               0 :       if (my_errno != HA_ERR_FOUND_DUPP_KEY)
    2600               0 :         goto err;
    2601               0 :       DBUG_DUMP("record", sort_param.record,
    2602                 :                 share->base.default_rec_buff_size);
    2603               0 :       _ma_check_print_warning(param,
    2604                 :                               "Duplicate key %2d for record at %10s against "
    2605                 :                               "new record at %10s",
    2606                 :                               info->errkey+1,
    2607                 :                               llstr(sort_param.current_filepos, llbuff),
    2608                 :                               llstr(info->dup_key_pos,llbuff2));
    2609               0 :       if (param->testflag & T_VERBOSE)
    2610                 :       {
    2611                 :         MARIA_KEY tmp_key;
    2612               0 :         MARIA_KEYDEF *keyinfo= share->keyinfo + info->errkey;
    2613               0 :         (*keyinfo->make_key)(info, &tmp_key, (uint) info->errkey,
    2614                 :                              info->lastkey_buff,
    2615                 :                              sort_param.record, 0L, 0);
    2616               0 :         _ma_print_key(stdout, &tmp_key);
    2617                 :       }
    2618               0 :       sort_info.dupp++;
    2619               0 :       if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
    2620                 :       {
    2621               0 :         param->testflag|=T_RETRY_WITHOUT_QUICK;
    2622               0 :         param->error_printed=1;
    2623               0 :         goto err;
    2624                 :       }
    2625                 :       /* purecov: begin tested */
    2626               0 :       if (block_record)
    2627                 :       {
    2628               0 :         sort_info.new_info->s->state.state.records--;
    2629               0 :         if ((*sort_info.new_info->s->write_record_abort)(sort_info.new_info))
    2630                 :         {
    2631               0 :           _ma_check_print_error(param,"Couldn't delete duplicate row");
    2632               0 :           goto err;
    2633                 :         }
    2634                 :       }
    2635                 :       /* purecov: end */
    2636                 :       continue;
    2637                 :     }
    2638               0 :     if (!block_record)
    2639                 :     {
    2640               0 :       if (_ma_sort_write_record(&sort_param))
    2641               0 :         goto err;
    2642                 :       /* Filepos is pointer to where next row will be stored */
    2643               0 :       sort_param.current_filepos= sort_param.filepos;
    2644                 :     }
    2645                 :   }
    2646               0 :   if (error > 0 || maria_write_data_suffix(&sort_info, !rep_quick) ||
    2647                 :       flush_io_cache(&sort_info.new_info->rec_cache) ||
    2648                 :       param->read_cache.error < 0)
    2649                 :     goto err;
    2650                 : 
    2651               0 :   if (param->testflag & T_WRITE_LOOP)
    2652                 :   {
    2653               0 :     VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
    2654                 :   }
    2655               0 :   if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
    2656                 :   {
    2657               0 :     _ma_check_print_warning(param,
    2658                 :                            "Can't change size of indexfile, error: %d",
    2659                 :                            my_errno);
    2660               0 :     goto err;
    2661                 :   }
    2662                 : 
    2663               0 :   if (rep_quick && del+sort_info.dupp != share->state.state.del)
    2664                 :   {
    2665               0 :     _ma_check_print_error(param,"Couldn't fix table with quick recovery: "
    2666                 :                           "Found wrong number of deleted records");
    2667               0 :     _ma_check_print_error(param,"Run recovery again without -q");
    2668               0 :     param->retry_repair=1;
    2669               0 :     param->testflag|=T_RETRY_WITHOUT_QUICK;
    2670               0 :     goto err;
    2671                 :   }
    2672                 : 
    2673               0 :   if (param->testflag & T_SAFE_REPAIR)
    2674                 :   {
    2675                 :     /* Don't repair if we loosed more than one row */
    2676               0 :     if (sort_info.new_info->s->state.state.records+1 < start_records)
    2677                 :     {
    2678               0 :       share->state.state.records= start_records;
    2679               0 :       goto err;
    2680                 :     }
    2681                 :   }
    2682                 : 
    2683               0 :   VOID(end_io_cache(&sort_info.new_info->rec_cache));
    2684               0 :   info->opt_flag&= ~WRITE_CACHE_USED;
    2685                 : 
    2686                 :   /*
    2687                 :     As we have read the data file (sort_get_next_record()) we may have
    2688                 :     cached, non-changed blocks of it in the page cache. We must throw them
    2689                 :     away as we are going to close their descriptor ('new_file'). We also want
    2690                 :     to flush any index block, so that it is ready for the upcoming sync.
    2691                 :   */
    2692               0 :   if (_ma_flush_table_files_before_swap(param, info))
    2693               0 :     goto err;
    2694                 : 
    2695               0 :   if (!rep_quick)
    2696                 :   {
    2697               0 :     sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
    2698               0 :     if (sort_info.new_info != sort_info.info)
    2699                 :     {
    2700               0 :       MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
    2701               0 :       if (maria_close(sort_info.new_info))
    2702                 :       {
    2703               0 :         _ma_check_print_error(param, "Got error %d on close", my_errno);
    2704               0 :         goto err;
    2705                 :       }
    2706               0 :       copy_data_file_state(&share->state, &save_state);
    2707               0 :       new_file= -1;
    2708               0 :       sort_info.new_info= info;
    2709                 :     }
    2710               0 :     share->state.version=(ulong) time((time_t*) 0);  /* Force reopen */
    2711                 : 
    2712                 :     /* Replace the actual file with the temporary file */
    2713               0 :     if (new_file >= 0)
    2714               0 :       my_close(new_file, MYF(MY_WME));
    2715               0 :     new_file= -1;
    2716               0 :     change_data_file_descriptor(info, -1);
    2717               0 :     if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
    2718                 :                                 DATA_TMP_EXT,
    2719                 :                                 (param->testflag & T_BACKUP_DATA ?
    2720                 :                                  MYF(MY_REDEL_MAKE_BACKUP): MYF(0)) |
    2721                 :                                 sync_dir) ||
    2722                 :         _ma_open_datafile(info, share, NullS, -1))
    2723                 :     {
    2724                 :       goto err;
    2725                 :     }
    2726                 :   }
    2727                 :   else
    2728                 :   {
    2729               0 :     share->state.state.data_file_length= sort_param.max_pos;
    2730                 :   }
    2731               0 :   if (param->testflag & T_CALC_CHECKSUM)
    2732               0 :     share->state.state.checksum= param->glob_crc;
    2733                 : 
    2734               0 :   if (!(param->testflag & T_SILENT))
    2735                 :   {
    2736               0 :     if (start_records != share->state.state.records)
    2737               0 :       printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
    2738                 :   }
    2739               0 :   if (sort_info.dupp)
    2740               0 :     _ma_check_print_warning(param,
    2741                 :                             "%s records have been removed",
    2742                 :                             llstr(sort_info.dupp,llbuff));
    2743                 : 
    2744               0 :   got_error= 0;
    2745                 :   /* If invoked by external program that uses thr_lock */
    2746               0 :   if (&share->state.state != info->state)
    2747               0 :     *info->state= *info->state_start= share->state.state;
    2748                 : 
    2749               0 : err:
    2750               0 :   if (scan_inited)
    2751               0 :     maria_scan_end(sort_info.info);
    2752               0 :   _ma_reset_state(info);
    2753                 : 
    2754               0 :   VOID(end_io_cache(&param->read_cache));
    2755               0 :   VOID(end_io_cache(&sort_info.new_info->rec_cache));
    2756               0 :   info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
    2757               0 :   sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
    2758                 :   /* this below could fail, shouldn't we detect error? */
    2759               0 :   if (got_error)
    2760                 :   {
    2761               0 :     if (! param->error_printed)
    2762               0 :       _ma_check_print_error(param,"%d for record at pos %s",my_errno,
    2763                 :                   llstr(sort_param.start_recpos,llbuff));
    2764               0 :     (void)_ma_flush_table_files_before_swap(param, info);
    2765               0 :     if (sort_info.new_info && sort_info.new_info != sort_info.info)
    2766                 :     {
    2767               0 :       unuse_data_file_descriptor(sort_info.new_info);
    2768               0 :       maria_close(sort_info.new_info);
    2769                 :     }
    2770               0 :     if (new_file >= 0)
    2771                 :     {
    2772               0 :       VOID(my_close(new_file,MYF(0)));
    2773               0 :       VOID(my_delete(param->temp_filename, MYF(MY_WME)));
    2774                 :     }
    2775               0 :     maria_mark_crashed_on_repair(info);
    2776                 :   }
    2777                 :   /* If caller had disabled logging it's not up to us to re-enable it */
    2778               0 :   if (reenable_logging)
    2779               0 :     _ma_reenable_logging_for_table(info, FALSE);
    2780                 : 
    2781               0 :   my_free(sort_param.rec_buff, MYF(MY_ALLOW_ZERO_PTR));
    2782               0 :   my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
    2783               0 :   my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
    2784               0 :   if (!got_error && (param->testflag & T_UNPACK))
    2785               0 :     restore_data_file_type(share);
    2786               0 :   share->state.changed|= (STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES |
    2787                 :                           STATE_NOT_ANALYZED | STATE_NOT_ZEROFILLED);
    2788               0 :   if (!rep_quick)
    2789               0 :     share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_MOVABLE);
    2790               0 :   DBUG_RETURN(got_error);
    2791                 : }
    2792                 : 
    2793                 : 
    2794                 : /* Uppdate keyfile when doing repair */
    2795                 : 
    2796                 : static int writekeys(MARIA_SORT_PARAM *sort_param)
    2797               0 : {
    2798                 :   uint i;
    2799               0 :   MARIA_HA *info=     sort_param->sort_info->info;
    2800               0 :   MARIA_SHARE *share= info->s;
    2801               0 :   uchar *record=    sort_param->record;
    2802                 :   uchar *key_buff;
    2803               0 :   my_off_t filepos=   sort_param->current_filepos;
    2804                 :   MARIA_KEY key;
    2805               0 :   DBUG_ENTER("writekeys");
    2806                 : 
    2807               0 :   key_buff= info->lastkey_buff+share->base.max_key_length;
    2808                 : 
    2809               0 :   for (i=0 ; i < share->base.keys ; i++)
    2810                 :   {
    2811               0 :     if (maria_is_key_active(share->state.key_map, i))
    2812                 :     {
    2813               0 :       if (share->keyinfo[i].flag & HA_FULLTEXT )
    2814                 :       {
    2815               0 :         if (_ma_ft_add(info, i, key_buff, record, filepos))
    2816                 :           goto err;
    2817                 :       }
    2818                 :       else
    2819                 :       {
    2820               0 :         if (!(*share->keyinfo[i].make_key)(info, &key, i, key_buff, record,
    2821                 :                                          filepos, 0))
    2822               0 :           goto err;
    2823               0 :         if ((*share->keyinfo[i].ck_insert)(info, &key))
    2824               0 :           goto err;
    2825                 :       }
    2826                 :     }
    2827                 :   }
    2828               0 :   DBUG_RETURN(0);
    2829                 : 
    2830               0 :  err:
    2831               0 :   if (my_errno == HA_ERR_FOUND_DUPP_KEY)
    2832                 :   {
    2833               0 :     info->errkey=(int) i;                    /* This key was found */
    2834               0 :     while ( i-- > 0 )
    2835                 :     {
    2836               0 :       if (maria_is_key_active(share->state.key_map, i))
    2837                 :       {
    2838               0 :         if (share->keyinfo[i].flag & HA_FULLTEXT)
    2839                 :         {
    2840               0 :           if (_ma_ft_del(info,i,key_buff,record,filepos))
    2841                 :             break;
    2842                 :         }
    2843                 :         else
    2844                 :         {
    2845               0 :           (*share->keyinfo[i].make_key)(info, &key, i, key_buff, record,
    2846                 :                                         filepos, 0);
    2847               0 :           if (_ma_ck_delete(info, &key))
    2848               0 :             break;
    2849                 :         }
    2850                 :       }
    2851                 :     }
    2852                 :   }
    2853                 :   /* Remove checksum that was added to glob_crc in sort_get_next_record */
    2854               0 :   if (sort_param->calc_checksum)
    2855               0 :     sort_param->sort_info->param->glob_crc-= info->cur_row.checksum;
    2856               0 :   DBUG_PRINT("error",("errno: %d",my_errno));
    2857               0 :   DBUG_RETURN(-1);
    2858                 : } /* writekeys */
    2859                 : 
    2860                 : 
    2861                 :         /* Change all key-pointers that points to a records */
    2862                 : 
    2863                 : int maria_movepoint(register MARIA_HA *info, uchar *record,
    2864                 :                     MARIA_RECORD_POS oldpos, MARIA_RECORD_POS newpos,
    2865                 :                     uint prot_key)
    2866               0 : {
    2867                 :   uint i;
    2868                 :   uchar *key_buff;
    2869               0 :   MARIA_SHARE *share= info->s;
    2870                 :   MARIA_PAGE page;
    2871               0 :   DBUG_ENTER("maria_movepoint");
    2872                 : 
    2873               0 :   key_buff= info->lastkey_buff + share->base.max_key_length;
    2874               0 :   for (i=0 ; i < share->base.keys; i++)
    2875                 :   {
    2876               0 :     if (i != prot_key && maria_is_key_active(share->state.key_map, i))
    2877                 :     {
    2878                 :       MARIA_KEY key;
    2879               0 :       (*share->keyinfo[i].make_key)(info, &key, i, key_buff, record, oldpos,
    2880                 :                                     0);
    2881               0 :       if (key.keyinfo->flag & HA_NOSAME)
    2882                 :       {                                 /* Change pointer direct */
    2883                 :         MARIA_KEYDEF *keyinfo;
    2884               0 :         keyinfo=share->keyinfo+i;
    2885               0 :         if (_ma_search(info, &key, (uint32) (SEARCH_SAME | SEARCH_SAVE_BUFF),
    2886                 :                        share->state.key_root[i]))
    2887               0 :           DBUG_RETURN(-1);
    2888               0 :         _ma_page_setup(&page, info, keyinfo, info->last_keypage,
    2889                 :                        info->keyread_buff);
    2890                 : 
    2891               0 :         _ma_dpointer(share, info->int_keypos - page.node -
    2892                 :                      share->rec_reflength,newpos);
    2893                 : 
    2894               0 :         if (_ma_write_keypage(&page, PAGECACHE_LOCK_LEFT_UNLOCKED,
    2895                 :                               DFLT_INIT_HITS))
    2896               0 :           DBUG_RETURN(-1);
    2897                 :       }
    2898                 :       else
    2899                 :       {                                 /* Change old key to new */
    2900               0 :         if (_ma_ck_delete(info, &key))
    2901               0 :           DBUG_RETURN(-1);
    2902               0 :         (*share->keyinfo[i].make_key)(info, &key, i, key_buff, record, newpos,
    2903                 :                                       0);
    2904               0 :         if (_ma_ck_write(info, &key))
    2905               0 :           DBUG_RETURN(-1);
    2906                 :       }
    2907                 :     }
    2908                 :   }
    2909               0 :   DBUG_RETURN(0);
    2910                 : } /* maria_movepoint */
    2911                 : 
    2912                 : 
    2913                 :         /* Tell system that we want all memory for our cache */
    2914                 : 
    2915                 : void maria_lock_memory(HA_CHECK *param __attribute__((unused)))
    2916               0 : {
    2917                 : #ifdef SUN_OS                           /* Key-cacheing thrases on sun 4.1 */
    2918                 :   if (param->opt_maria_lock_memory)
    2919                 :   {
    2920                 :     int success = mlockall(MCL_CURRENT);        /* or plock(DATLOCK); */
    2921                 :     if (geteuid() == 0 && success != 0)
    2922                 :       _ma_check_print_warning(param,
    2923                 :                              "Failed to lock memory. errno %d",my_errno);
    2924                 :   }
    2925                 : #endif
    2926                 : } /* maria_lock_memory */
    2927                 : 
    2928                 : 
    2929                 : /**
    2930                 :    Flush all changed blocks to disk.
    2931                 : 
    2932                 :    We release blocks as it's unlikely that they would all be needed soon.
    2933                 :    This function needs to be called before swapping data or index files or
    2934                 :    syncing them.
    2935                 : 
    2936                 :    @param  param           description of the repair operation
    2937                 :    @param  info            table
    2938                 : */
    2939                 : 
    2940                 : static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
    2941                 :                                                  MARIA_HA *info)
    2942               0 : {
    2943               0 :   DBUG_ENTER("_ma_flush_table_files_before_swap");
    2944               0 :   if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
    2945                 :                             FLUSH_RELEASE, FLUSH_RELEASE))
    2946                 :   {
    2947               0 :     _ma_check_print_error(param, "%d when trying to write buffers", my_errno);
    2948               0 :     DBUG_RETURN(TRUE);
    2949                 :   }
    2950               0 :   DBUG_RETURN(FALSE);
    2951                 : }
    2952                 : 
    2953                 : 
    2954                 :         /* Sort index for more efficent reads */
    2955                 : 
    2956                 : int maria_sort_index(HA_CHECK *param, register MARIA_HA *info, char *name)
    2957               0 : {
    2958                 :   reg2 uint key;
    2959                 :   reg1 MARIA_KEYDEF *keyinfo;
    2960                 :   File new_file;
    2961                 :   my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
    2962                 :   uint r_locks,w_locks;
    2963                 :   int old_lock;
    2964               0 :   MARIA_SHARE *share= info->s;
    2965                 :   MARIA_STATE_INFO old_state;
    2966                 :   myf sync_dir= ((share->now_transactional && !share->temporary) ?
    2967               0 :                  MY_SYNC_DIR : 0);
    2968               0 :   DBUG_ENTER("maria_sort_index");
    2969                 : 
    2970                 :   /* cannot sort index files with R-tree indexes */
    2971               0 :   for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
    2972               0 :        key++,keyinfo++)
    2973               0 :     if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
    2974               0 :       DBUG_RETURN(0);
    2975                 : 
    2976               0 :   if (!(param->testflag & T_SILENT))
    2977               0 :     printf("- Sorting index for MARIA-table '%s'\n",name);
    2978                 : 
    2979               0 :   if (protect_against_repair_crash(info, param, FALSE))
    2980               0 :     DBUG_RETURN(1);
    2981                 : 
    2982                 :   /* Get real path for index file */
    2983               0 :   fn_format(param->temp_filename,name,"", MARIA_NAME_IEXT,2+4+32);
    2984               0 :   if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename,
    2985                 :                                     "", INDEX_TMP_EXT,2+4),
    2986                 :                           0,param->tmpfile_createflag,MYF(0))) <= 0)
    2987                 :   {
    2988               0 :     _ma_check_print_error(param,"Can't create new tempfile: '%s'",
    2989                 :                          param->temp_filename);
    2990               0 :     DBUG_RETURN(-1);
    2991                 :   }
    2992               0 :   if (maria_filecopy(param, new_file, share->kfile.file, 0L,
    2993                 :                      (ulong) share->base.keystart, "headerblock"))
    2994               0 :     goto err;
    2995                 : 
    2996               0 :   param->new_file_pos=share->base.keystart;
    2997               0 :   for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
    2998               0 :        key++,keyinfo++)
    2999                 :   {
    3000               0 :     if (! maria_is_key_active(share->state.key_map, key))
    3001               0 :       continue;
    3002                 : 
    3003               0 :     if (share->state.key_root[key] != HA_OFFSET_ERROR)
    3004                 :     {
    3005               0 :       index_pos[key]=param->new_file_pos;    /* Write first block here */
    3006               0 :       if (sort_one_index(param,info,keyinfo,share->state.key_root[key],
    3007                 :                          new_file))
    3008                 :         goto err;
    3009                 :     }
    3010                 :     else
    3011               0 :       index_pos[key]= HA_OFFSET_ERROR;          /* No blocks */
    3012                 :   }
    3013                 : 
    3014                 :   /* Flush key cache for this file if we are calling this outside maria_chk */
    3015               0 :   flush_pagecache_blocks(share->pagecache, &share->kfile,
    3016                 :                          FLUSH_IGNORE_CHANGED);
    3017                 : 
    3018               0 :   share->state.version=(ulong) time((time_t*) 0);
    3019               0 :   old_state= share->state;                   /* save state if not stored */
    3020               0 :   r_locks=   share->r_locks;
    3021               0 :   w_locks=   share->w_locks;
    3022               0 :   old_lock=  info->lock_type;
    3023                 : 
    3024                 :         /* Put same locks as old file */
    3025               0 :   share->r_locks= share->w_locks= share->tot_locks= 0;
    3026               0 :   (void) _ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
    3027               0 :   pthread_mutex_lock(&share->intern_lock);
    3028               0 :   VOID(my_close(share->kfile.file, MYF(MY_WME)));
    3029               0 :   share->kfile.file = -1;
    3030               0 :   pthread_mutex_unlock(&share->intern_lock);
    3031               0 :   VOID(my_close(new_file,MYF(MY_WME)));
    3032               0 :   if (maria_change_to_newfile(share->index_file_name.str, MARIA_NAME_IEXT,
    3033                 :                               INDEX_TMP_EXT, sync_dir) ||
    3034                 :       _ma_open_keyfile(share))
    3035                 :     goto err2;
    3036               0 :   info->lock_type= F_UNLCK;                  /* Force maria_readinfo to lock */
    3037               0 :   _ma_readinfo(info,F_WRLCK,0);                 /* Will lock the table */
    3038               0 :   info->lock_type=  old_lock;
    3039               0 :   share->r_locks=   r_locks;
    3040               0 :   share->w_locks=   w_locks;
    3041               0 :   share->tot_locks= r_locks+w_locks;
    3042               0 :   share->state=     old_state;                       /* Restore old state */
    3043                 : 
    3044               0 :   share->state.state.key_file_length=param->new_file_pos;
    3045               0 :   info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
    3046               0 :   for (key=0 ; key < share->base.keys ; key++)
    3047               0 :     share->state.key_root[key]=index_pos[key];
    3048               0 :   share->state.key_del=  HA_OFFSET_ERROR;
    3049                 : 
    3050               0 :   share->state.changed&= ~STATE_NOT_SORTED_PAGES;
    3051               0 :   DBUG_EXECUTE_IF("maria_flush_whole_log",
    3052                 :                   {
    3053                 :                     DBUG_PRINT("maria_flush_whole_log", ("now"));
    3054                 :                     translog_flush(translog_get_horizon());
    3055                 :                   });
    3056               0 :   DBUG_EXECUTE_IF("maria_crash_sort_index",
    3057                 :                   {
    3058                 :                     DBUG_PRINT("maria_crash_sort_index", ("now"));
    3059                 :                     DBUG_ABORT();
    3060                 :                   });
    3061               0 :   DBUG_RETURN(0);
    3062                 : 
    3063               0 : err:
    3064               0 :   VOID(my_close(new_file,MYF(MY_WME)));
    3065               0 : err2:
    3066               0 :   VOID(my_delete(param->temp_filename,MYF(MY_WME)));
    3067               0 :   DBUG_RETURN(-1);
    3068                 : } /* maria_sort_index */
    3069                 : 
    3070                 : 
    3071                 : /**
    3072                 :   @brief put CRC on the page
    3073                 : 
    3074                 :   @param buff            reference on the page buffer.
    3075                 :   @param pos             position of the page in the file.
    3076                 :   @param length          length of the page
    3077                 : */
    3078                 : 
    3079                 : static void put_crc(uchar *buff, my_off_t pos, MARIA_SHARE *share)
    3080               0 : {
    3081               0 :   maria_page_crc_set_index(buff, (pgcache_page_no_t) (pos / share->block_size),
    3082                 :                            (uchar*) share);
    3083                 : }
    3084                 : 
    3085                 : 
    3086                 : /* Sort index blocks recursive using one index */
    3087                 : 
    3088                 : static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
    3089                 :                           MARIA_KEYDEF *keyinfo,
    3090                 :                           my_off_t pagepos, File new_file)
    3091               0 : {
    3092                 :   uint length,nod_flag;
    3093                 :   uchar *buff,*keypos,*endpos;
    3094                 :   my_off_t new_page_pos,next_page;
    3095               0 :   MARIA_SHARE *share= info->s;
    3096                 :   MARIA_KEY key;
    3097                 :   MARIA_PAGE page;
    3098               0 :   DBUG_ENTER("sort_one_index");
    3099                 : 
    3100                 :   /* cannot walk over R-tree indices */
    3101               0 :   DBUG_ASSERT(keyinfo->key_alg != HA_KEY_ALG_RTREE);
    3102               0 :   new_page_pos=param->new_file_pos;
    3103               0 :   param->new_file_pos+=keyinfo->block_length;
    3104               0 :   key.keyinfo= keyinfo;
    3105               0 :   key.data= info->lastkey_buff;
    3106                 : 
    3107               0 :   if (!(buff= (uchar*) my_alloca((uint) keyinfo->block_length)))
    3108                 :   {
    3109               0 :     _ma_check_print_error(param,"Not enough memory for key block");
    3110               0 :     DBUG_RETURN(-1);
    3111                 :   }
    3112               0 :   if (_ma_fetch_keypage(&page, info, keyinfo, pagepos,
    3113                 :                         PAGECACHE_LOCK_LEFT_UNLOCKED,
    3114                 :                         DFLT_INIT_HITS, buff, 0))
    3115                 :   {
    3116               0 :     report_keypage_fault(param, info, pagepos);
    3117               0 :     goto err;
    3118                 :   }
    3119                 : 
    3120               0 :   if ((nod_flag= page.node) || keyinfo->flag & HA_FULLTEXT)
    3121                 :   {
    3122               0 :     keypos= page.buff + share->keypage_header + nod_flag;
    3123               0 :     endpos= page.buff + page.size;
    3124                 : 
    3125                 :     for ( ;; )
    3126                 :     {
    3127               0 :       if (nod_flag)
    3128                 :       {
    3129               0 :         next_page= _ma_kpos(nod_flag,keypos);
    3130                 :         /* Save new pos */
    3131               0 :         _ma_kpointer(info,keypos-nod_flag,param->new_file_pos);
    3132               0 :         if (sort_one_index(param,info,keyinfo,next_page,new_file))
    3133                 :         {
    3134               0 :           DBUG_PRINT("error",
    3135                 :                      ("From page: %ld, keyoffset: %lu  used_length: %d",
    3136                 :                       (ulong) pagepos, (ulong) (keypos - buff),
    3137                 :                       (int) page.size));
    3138               0 :           DBUG_DUMP("buff", page.buff, page.size);
    3139               0 :           goto err;
    3140                 :         }
    3141                 :       }
    3142               0 :       if (keypos >= endpos ||
    3143                 :           !(*keyinfo->get_key)(&key, page.flag, nod_flag, &keypos))
    3144                 :         break;
    3145               0 :       DBUG_ASSERT(keypos <= endpos);
    3146               0 :       if (keyinfo->flag & HA_FULLTEXT)
    3147                 :       {
    3148                 :         uint off;
    3149                 :         int  subkeys;
    3150               0 :         get_key_full_length_rdonly(off, key.data);
    3151               0 :         subkeys= ft_sintXkorr(key.data + off);
    3152               0 :         if (subkeys < 0)
    3153                 :         {
    3154               0 :           next_page= _ma_row_pos_from_key(&key);
    3155               0 :           _ma_dpointer(share, keypos - nod_flag - share->rec_reflength,
    3156                 :                        param->new_file_pos); /* Save new pos */
    3157               0 :           if (sort_one_index(param,info,&share->ft2_keyinfo,
    3158                 :                              next_page,new_file))
    3159                 :             goto err;
    3160                 :         }
    3161                 :       }
    3162                 :     }
    3163                 :   }
    3164                 : 
    3165                 :   /* Fill block with zero and write it to the new index file */
    3166               0 :   length= page.size;
    3167               0 :   bzero(buff+length,keyinfo->block_length-length);
    3168               0 :   put_crc(buff, new_page_pos, share);
    3169               0 :   if (my_pwrite(new_file, buff,(uint) keyinfo->block_length,
    3170                 :                 new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
    3171                 :   {
    3172               0 :     _ma_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
    3173               0 :     goto err;
    3174                 :   }
    3175                 :   my_afree(buff);
    3176               0 :   DBUG_RETURN(0);
    3177               0 : err:
    3178                 :   my_afree(buff);
    3179               0 :   DBUG_RETURN(1);
    3180                 : } /* sort_one_index */
    3181                 : 
    3182                 : 
    3183                 : /**
    3184                 :    @brief Fill empty space in index file with zeroes
    3185                 : 
    3186                 :    @return
    3187                 :    @retval 0  Ok
    3188                 :    @retval 1  Error
    3189                 : */
    3190                 : 
    3191                 : static my_bool maria_zerofill_index(HA_CHECK *param, MARIA_HA *info,
    3192                 :                                     const char *name)
    3193               0 : {
    3194               0 :   MARIA_SHARE *share= info->s;
    3195                 :   MARIA_PINNED_PAGE page_link;
    3196                 :   char llbuff[21];
    3197                 :   uchar *buff;
    3198                 :   pgcache_page_no_t page;
    3199                 :   my_off_t pos;
    3200               0 :   my_off_t key_file_length= share->state.state.key_file_length;
    3201               0 :   uint block_size= share->block_size;
    3202                 :   my_bool zero_lsn= (share->base.born_transactional &&
    3203               0 :                      !(param->testflag & T_ZEROFILL_KEEP_LSN));
    3204               0 :   DBUG_ENTER("maria_zerofill_index");
    3205                 : 
    3206               0 :   if (!(param->testflag & T_SILENT))
    3207               0 :     printf("- Zerofilling index for MARIA-table '%s'\n",name);
    3208                 : 
    3209                 :   /* Go through the index file */
    3210               0 :   for (pos= share->base.keystart, page= (ulonglong) (pos / block_size);
    3211               0 :        pos < key_file_length;
    3212               0 :        pos+= block_size, page++)
    3213                 :   {
    3214                 :     uint length;
    3215               0 :     if (!(buff= pagecache_read(share->pagecache,
    3216                 :                                &share->kfile, page,
    3217                 :                                DFLT_INIT_HITS, 0,
    3218                 :                                PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
    3219                 :                                &page_link.link)))
    3220                 :     {
    3221               0 :       pagecache_unlock_by_link(share->pagecache, page_link.link,
    3222                 :                                PAGECACHE_LOCK_WRITE_UNLOCK,
    3223                 :                                PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
    3224                 :                                LSN_IMPOSSIBLE, 0, FALSE);
    3225               0 :       _ma_check_print_error(param,
    3226                 :                             "Page %9s: Got error %d when reading index file",
    3227                 :                             llstr(pos, llbuff), my_errno);
    3228               0 :       DBUG_RETURN(1);
    3229                 :     }
    3230               0 :     if (zero_lsn)
    3231               0 :       bzero(buff, LSN_SIZE);
    3232                 : 
    3233               0 :     if (share->base.born_transactional)
    3234                 :     {
    3235               0 :       uint keynr= _ma_get_keynr(share, buff);
    3236               0 :       if (keynr != MARIA_DELETE_KEY_NR)
    3237                 :       {
    3238                 :         MARIA_PAGE page;
    3239               0 :         DBUG_ASSERT(keynr < share->base.keys);
    3240                 : 
    3241               0 :         _ma_page_setup(&page, info, share->keyinfo + keynr, pos, buff);
    3242               0 :         if (_ma_compact_keypage(&page, ~(TrID) 0))
    3243                 :         {
    3244               0 :           _ma_check_print_error(param,
    3245                 :                                 "Page %9s: Got error %d when reading index "
    3246                 :                                 "file",
    3247                 :                                 llstr(pos, llbuff), my_errno);
    3248               0 :           DBUG_RETURN(1);
    3249                 :         }
    3250                 :       }
    3251                 :     }
    3252                 : 
    3253               0 :     length= _ma_get_page_used(share, buff);
    3254               0 :     DBUG_ASSERT(length <= block_size);
    3255               0 :     if (length < block_size)
    3256               0 :       bzero(buff + length, block_size - length);
    3257               0 :     pagecache_unlock_by_link(share->pagecache, page_link.link,
    3258                 :                              PAGECACHE_LOCK_WRITE_UNLOCK,
    3259                 :                              PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
    3260                 :                              LSN_IMPOSSIBLE, 1, FALSE);
    3261                 :   }
    3262               0 :   if (flush_pagecache_blocks(share->pagecache, &share->kfile,
    3263                 :                              FLUSH_FORCE_WRITE))
    3264               0 :     DBUG_RETURN(1);
    3265               0 :   DBUG_RETURN(0);
    3266                 : }
    3267                 : 
    3268                 : 
    3269                 : /**
    3270                 :    @brief Fill empty space in data file with zeroes
    3271                 : 
    3272                 :    @todo
    3273                 :    Zerofill all pages marked in bitmap as empty and change them to
    3274                 :    be of type UNALLOCATED_PAGE
    3275                 : 
    3276                 :    @return
    3277                 :    @retval 0  Ok
    3278                 :    @retval 1  Error
    3279                 : */
    3280                 : 
    3281                 : static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
    3282                 :                                    const char *name)
    3283               0 : {
    3284               0 :   MARIA_SHARE *share= info->s;
    3285                 :   MARIA_PINNED_PAGE page_link;
    3286                 :   char llbuff[21];
    3287                 :   my_off_t pos;
    3288                 :   pgcache_page_no_t page;
    3289               0 :   uint block_size= share->block_size;
    3290               0 :   MARIA_FILE_BITMAP *bitmap= &share->bitmap;
    3291               0 :   my_bool zero_lsn= !(param->testflag & T_ZEROFILL_KEEP_LSN), error;
    3292               0 :   DBUG_ENTER("maria_zerofill_data");
    3293                 : 
    3294                 :   /* This works only with BLOCK_RECORD files */
    3295               0 :   if (share->data_file_type != BLOCK_RECORD)
    3296               0 :     DBUG_RETURN(0);
    3297                 : 
    3298               0 :   if (!(param->testflag & T_SILENT))
    3299               0 :     printf("- Zerofilling data  for MARIA-table '%s'\n",name);
    3300                 : 
    3301                 :   /* Go through the record file */
    3302               0 :   for (page= 1, pos= block_size;
    3303               0 :        pos < share->state.state.data_file_length;
    3304               0 :        pos+= block_size, page++)
    3305                 :   {
    3306                 :     uchar *buff;
    3307                 :     enum en_page_type page_type;
    3308                 : 
    3309                 :     /* Ignore bitmap pages */
    3310               0 :     if ((page % share->bitmap.pages_covered) == 0)
    3311               0 :       continue;
    3312               0 :     if (!(buff= pagecache_read(share->pagecache,
    3313                 :                                &info->dfile,
    3314                 :                                page, 1, 0,
    3315                 :                                PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
    3316                 :                                &page_link.link)))
    3317                 :     {
    3318               0 :       _ma_check_print_error(param,
    3319                 :                             "Page %9s:  Got error: %d when reading datafile",
    3320                 :                             llstr(pos, llbuff), my_errno);
    3321               0 :       goto err;
    3322                 :     }
    3323               0 :     page_type= (enum en_page_type) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK);
    3324               0 :     switch (page_type) {
    3325                 :     case UNALLOCATED_PAGE:
    3326               0 :       if (zero_lsn)
    3327               0 :         bzero(buff, block_size);
    3328                 :       else
    3329               0 :         bzero(buff + LSN_SIZE, block_size - LSN_SIZE);
    3330                 :       break;
    3331                 :     case BLOB_PAGE:
    3332               0 :       if (_ma_bitmap_get_page_bits(info, bitmap, page) == 0)
    3333                 :       {
    3334                 :         /* Unallocated page */
    3335               0 :         if (zero_lsn)
    3336               0 :           bzero(buff, block_size);
    3337                 :         else
    3338               0 :           bzero(buff + LSN_SIZE, block_size - LSN_SIZE);
    3339                 :       }
    3340                 :       else
    3341               0 :         if (zero_lsn)
    3342               0 :           bzero(buff, LSN_SIZE);
    3343                 :       break;
    3344                 :     case HEAD_PAGE:
    3345                 :     case TAIL_PAGE:
    3346                 :     {
    3347               0 :       uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
    3348                 :       uint offset, dir_start;
    3349                 :       uchar *dir;
    3350                 : 
    3351               0 :       if (zero_lsn)
    3352               0 :         bzero(buff, LSN_SIZE);
    3353               0 :       if (max_entry != 0)
    3354                 :       {
    3355               0 :         my_bool is_head_page= (page_type == HEAD_PAGE);
    3356               0 :         dir= dir_entry_pos(buff, block_size, max_entry - 1);
    3357               0 :         _ma_compact_block_page(buff, block_size, max_entry -1, 0,
    3358                 :                                is_head_page ? ~(TrID) 0 : 0,
    3359                 :                                is_head_page ?
    3360                 :                                share->base.min_block_length : 0);
    3361                 :         /* compactation may have increased free space */
    3362               0 :         if (_ma_bitmap_set(info, page, is_head_page,
    3363                 :                            uint2korr(buff + EMPTY_SPACE_OFFSET)))
    3364               0 :           goto err;
    3365                 : 
    3366                 :         /* Zerofill the not used part */
    3367               0 :         offset= uint2korr(dir) + uint2korr(dir+2);
    3368               0 :         dir_start= (uint) (dir - buff);
    3369               0 :         DBUG_ASSERT(dir_start >= offset);
    3370               0 :         if (dir_start > offset)
    3371               0 :           bzero(buff + offset, dir_start - offset);
    3372                 :       }
    3373                 :       break;
    3374                 :     }
    3375                 :     default:
    3376               0 :       _ma_check_print_error(param,
    3377                 :                             "Page %9s:  Found unrecognizable block of type %d",
    3378                 :                             llstr(pos, llbuff), page_type);
    3379               0 :       goto err;
    3380                 :     }
    3381               0 :     pagecache_unlock_by_link(share->pagecache, page_link.link,
    3382                 :                              PAGECACHE_LOCK_WRITE_UNLOCK,
    3383                 :                              PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
    3384                 :                              LSN_IMPOSSIBLE, 1, FALSE);
    3385                 :   }
    3386               0 :   error= _ma_bitmap_flush(share);
    3387               0 :   if (flush_pagecache_blocks(share->pagecache, &info->dfile,
    3388                 :                              FLUSH_FORCE_WRITE))
    3389               0 :     error= 1;
    3390               0 :   DBUG_RETURN(error);
    3391                 : 
    3392               0 : err:
    3393               0 :   pagecache_unlock_by_link(share->pagecache, page_link.link,
    3394                 :                            PAGECACHE_LOCK_WRITE_UNLOCK,
    3395                 :                            PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
    3396                 :                            LSN_IMPOSSIBLE, 0, FALSE);
    3397                 :   /* flush what was changed so far */
    3398               0 :   (void) _ma_bitmap_flush(share);
    3399               0 :   (void) flush_pagecache_blocks(share->pagecache, &info->dfile,
    3400                 :                                 FLUSH_FORCE_WRITE);
    3401                 : 
    3402               0 :   DBUG_RETURN(1);
    3403                 : }
    3404                 : 
    3405                 : 
    3406                 : /**
    3407                 :    @brief Fill empty space in index and data files with zeroes
    3408                 : 
    3409                 :    @return
    3410                 :    @retval 0  Ok
    3411                 :    @retval 1  Error
    3412                 : */
    3413                 : 
    3414                 : int maria_zerofill(HA_CHECK *param, MARIA_HA *info, const char *name)
    3415               0 : {
    3416                 :   my_bool error, reenable_logging,
    3417               0 :     zero_lsn= !(param->testflag & T_ZEROFILL_KEEP_LSN);
    3418               0 :   MARIA_SHARE *share= info->s;
    3419               0 :   DBUG_ENTER("maria_zerofill");
    3420               0 :   if ((reenable_logging= share->now_transactional))
    3421               0 :     _ma_tmp_disable_logging_for_table(info, 0);
    3422               0 :   if (!(error= (maria_zerofill_index(param, info, name) ||
    3423                 :                 maria_zerofill_data(param, info, name) ||
    3424                 :                 _ma_set_uuid(info, 0))))
    3425                 :   {
    3426                 :     /*
    3427                 :       Mark that we have done zerofill of data and index. If we zeroed pages'
    3428                 :       LSN, table is movable.
    3429                 :     */
    3430               0 :     share->state.changed&= ~STATE_NOT_ZEROFILLED;
    3431               0 :     if (zero_lsn)
    3432                 :     {
    3433               0 :       share->state.changed&= ~(STATE_NOT_MOVABLE | STATE_MOVED);
    3434                 :       /* Table should get new LSNs */
    3435               0 :       share->state.create_rename_lsn= share->state.is_of_horizon=
    3436                 :         share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
    3437                 :     }
    3438                 :     /* Ensure state is later flushed to disk, if within maria_chk */
    3439               0 :     info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
    3440                 : 
    3441                 :     /* Reset create_trid to make file comparable */
    3442               0 :     share->state.create_trid= 0;
    3443                 :   }
    3444               0 :   if (reenable_logging)
    3445               0 :     _ma_reenable_logging_for_table(info, FALSE);
    3446               0 :   DBUG_RETURN(error);
    3447                 : }
    3448                 : 
    3449                 : 
    3450                 : /*
    3451                 :   Let temporary file replace old file.
    3452                 :   This assumes that the new file was created in the same
    3453                 :   directory as given by realpath(filename).
    3454                 :   This will ensure that any symlinks that are used will still work.
    3455                 :   Copy stats from old file to new file, deletes orignal and
    3456                 :   changes new file name to old file name
    3457                 : */
    3458                 : 
    3459                 : int maria_change_to_newfile(const char * filename, const char * old_ext,
    3460                 :                             const char * new_ext, myf MyFlags)
    3461               0 : {
    3462                 :   char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
    3463                 : #ifdef USE_RAID
    3464                 :   if (raid_chunks)
    3465                 :     return my_raid_redel(fn_format(old_filename,filename,"",old_ext,2+4),
    3466                 :                          fn_format(new_filename,filename,"",new_ext,2+4),
    3467                 :                          raid_chunks,
    3468                 :                          MYF(MY_WME | MY_LINK_WARNING | MyFlags));
    3469                 : #endif
    3470                 :   /* Get real path to filename */
    3471               0 :   (void) fn_format(old_filename,filename,"",old_ext,2+4+32);
    3472               0 :   return my_redel(old_filename,
    3473                 :                   fn_format(new_filename,old_filename,"",new_ext,2+4),
    3474                 :                   MYF(MY_WME | MY_LINK_WARNING | MyFlags));
    3475                 : } /* maria_change_to_newfile */
    3476                 : 
    3477                 : 
    3478                 : /* Copy a block between two files */
    3479                 : 
    3480                 : int maria_filecopy(HA_CHECK *param, File to,File from,my_off_t start,
    3481                 :                    my_off_t length, const char *type)
    3482               0 : {
    3483                 :   uchar tmp_buff[IO_SIZE], *buff;
    3484                 :   ulong buff_length;
    3485               0 :   DBUG_ENTER("maria_filecopy");
    3486                 : 
    3487               0 :   buff_length=(ulong) min(param->write_buffer_length,length);
    3488               0 :   if (!(buff=my_malloc(buff_length,MYF(0))))
    3489                 :   {
    3490               0 :     buff=tmp_buff; buff_length=IO_SIZE;
    3491                 :   }
    3492                 : 
    3493               0 :   VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
    3494               0 :   while (length > buff_length)
    3495                 :   {
    3496               0 :     if (my_read(from, buff, buff_length, MYF(MY_NABP)) ||
    3497                 :         my_write(to,  buff, buff_length, param->myf_rw))
    3498                 :       goto err;
    3499               0 :     length-= buff_length;
    3500                 :   }
    3501               0 :   if (my_read(from, buff, (size_t) length,MYF(MY_NABP)) ||
    3502                 :       my_write(to,  buff, (size_t) length,param->myf_rw))
    3503                 :     goto err;
    3504               0 :   if (buff != tmp_buff)
    3505               0 :     my_free(buff,MYF(0));
    3506               0 :   DBUG_RETURN(0);
    3507               0 : err:
    3508               0 :   if (buff != tmp_buff)
    3509               0 :     my_free(buff,MYF(0));
    3510               0 :   _ma_check_print_error(param,"Can't copy %s to tempfile, error %d",
    3511                 :                        type,my_errno);
    3512               0 :   DBUG_RETURN(1);
    3513                 : }
    3514                 : 
    3515                 : 
    3516                 : /*
    3517                 :   Repair table or given index using sorting
    3518                 : 
    3519                 :   SYNOPSIS
    3520                 :     maria_repair_by_sort()
    3521                 :     param               Repair parameters
    3522                 :     info                MARIA handler to repair
    3523                 :     name                Name of table (for warnings)
    3524                 :     rep_quick           set to <> 0 if we should not change data file
    3525                 : 
    3526                 :   RESULT
    3527                 :     0   ok
    3528                 :     <>0   Error
    3529                 : */
    3530                 : 
    3531                 : int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
    3532                 :                          const char * name, my_bool rep_quick)
    3533               0 : {
    3534                 :   int got_error;
    3535                 :   uint i;
    3536                 :   ha_rows start_records;
    3537                 :   my_off_t new_header_length, org_header_length, del;
    3538                 :   File new_file;
    3539                 :   MARIA_SORT_PARAM sort_param;
    3540               0 :   MARIA_SHARE *share= info->s;
    3541                 :   HA_KEYSEG *keyseg;
    3542                 :   double  *rec_per_key_part;
    3543                 :   char llbuff[22];
    3544                 :   MARIA_SORT_INFO sort_info;
    3545                 :   ulonglong key_map;
    3546                 :   myf sync_dir= ((share->now_transactional && !share->temporary) ?
    3547               0 :                  MY_SYNC_DIR : 0);
    3548               0 :   my_bool scan_inited= 0;
    3549               0 :   DBUG_ENTER("maria_repair_by_sort");
    3550               0 :   LINT_INIT(key_map);
    3551                 : 
    3552               0 :   got_error= 1;
    3553               0 :   new_file= -1;
    3554               0 :   start_records= share->state.state.records;
    3555               0 :   if (!(param->testflag & T_SILENT))
    3556                 :   {
    3557               0 :     printf("- recovering (with sort) MARIA-table '%s'\n",name);
    3558               0 :     printf("Data records: %s\n", llstr(start_records,llbuff));
    3559                 :   }
    3560                 : 
    3561               0 :   if (initialize_variables_for_repair(param, &sort_info, &sort_param, info,
    3562                 :                                       rep_quick))
    3563               0 :     goto err;
    3564                 : 
    3565               0 :   org_header_length= share->pack.header_length;
    3566               0 :   new_header_length= (param->testflag & T_UNPACK) ? 0 : org_header_length;
    3567               0 :   sort_param.filepos= new_header_length;
    3568                 : 
    3569               0 :   if (!rep_quick)
    3570                 :   {
    3571                 :     /* Get real path for data file */
    3572               0 :     if ((new_file=my_create(fn_format(param->temp_filename,
    3573                 :                                       share->data_file_name.str, "",
    3574                 :                                       DATA_TMP_EXT, 2+4),
    3575                 :                             0,param->tmpfile_createflag,
    3576                 :                             MYF(0))) < 0)
    3577                 :     {
    3578               0 :       _ma_check_print_error(param,"Can't create new tempfile: '%s'",
    3579                 :                            param->temp_filename);
    3580               0 :       goto err;
    3581                 :     }
    3582               0 :     if (new_header_length &&
    3583                 :         maria_filecopy(param, new_file, info->dfile.file, 0L,
    3584                 :                        new_header_length, "datafile-header"))
    3585               0 :       goto err;
    3586                 : 
    3587               0 :     share->state.dellink= HA_OFFSET_ERROR;
    3588               0 :     info->rec_cache.file= new_file;             /* For sort_delete_record */
    3589               0 :     if (share->data_file_type == BLOCK_RECORD ||
    3590                 :         (param->testflag & T_UNPACK))
    3591                 :     {
    3592               0 :       if (create_new_data_handle(&sort_param, new_file))
    3593               0 :         goto err;
    3594               0 :       sort_info.new_info->rec_cache.file= new_file;
    3595                 :     }
    3596                 :   }
    3597                 : 
    3598               0 :   if (!(sort_info.key_block=
    3599                 :         alloc_key_blocks(param,
    3600                 :                          (uint) param->sort_key_blocks,
    3601                 :                          share->base.max_key_block_length)))
    3602               0 :     goto err;
    3603               0 :   sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
    3604                 : 
    3605               0 :   if (share->data_file_type != BLOCK_RECORD)
    3606                 :   {
    3607                 :     /* We need a read buffer to read rows in big blocks */
    3608               0 :     if (init_io_cache(&param->read_cache, info->dfile.file,
    3609                 :                       (uint) param->read_buffer_length,
    3610                 :                       READ_CACHE, org_header_length, 1, MYF(MY_WME)))
    3611               0 :       goto err;
    3612                 :   }
    3613               0 :   if (sort_info.new_info->s->data_file_type != BLOCK_RECORD)
    3614                 :   {
    3615                 :     /* When writing to not block records, we need a write buffer */
    3616               0 :     if (!rep_quick)
    3617                 :     {
    3618               0 :       if (init_io_cache(&sort_info.new_info->rec_cache, new_file,
    3619                 :                         (uint) param->write_buffer_length,
    3620                 :                         WRITE_CACHE, new_header_length, 1,
    3621                 :                         MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw))
    3622               0 :         goto err;
    3623               0 :       sort_info.new_info->opt_flag|= WRITE_CACHE_USED;
    3624                 :     }
    3625                 :   }
    3626                 : 
    3627               0 :   if (!(sort_param.record=
    3628                 :         (uchar*) my_malloc((size_t) share->base.default_rec_buff_size,
    3629                 :                            MYF(0))) ||
    3630                 :       _ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
    3631                 :                        share->base.default_rec_buff_size))
    3632                 :   {
    3633               0 :     _ma_check_print_error(param, "Not enough memory for extra record");
    3634               0 :     goto err;
    3635                 :   }
    3636                 : 
    3637                 :   /* Optionally drop indexes and optionally modify the key_map */
    3638               0 :   maria_drop_all_indexes(param, info, FALSE);
    3639               0 :   key_map= share->state.key_map;
    3640               0 :   if (param->testflag & T_CREATE_MISSING_KEYS)
    3641                 :   {
    3642                 :     /* Invert the copied key_map to recreate all disabled indexes. */
    3643               0 :     key_map= ~key_map;
    3644                 :   }
    3645                 : 
    3646               0 :   param->read_cache.end_of_file= sort_info.filelength;
    3647               0 :   sort_param.wordlist=NULL;
    3648               0 :   init_alloc_root(&sort_param.wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
    3649                 : 
    3650               0 :   sort_param.key_cmp=sort_key_cmp;
    3651               0 :   sort_param.lock_in_memory=maria_lock_memory;
    3652               0 :   sort_param.tmpdir=param->tmpdir;
    3653               0 :   sort_param.master =1;
    3654                 : 
    3655               0 :   del=share->state.state.del;
    3656                 : 
    3657               0 :   rec_per_key_part= param->new_rec_per_key_part;
    3658               0 :   for (sort_param.key=0 ; sort_param.key < share->base.keys ;
    3659               0 :        rec_per_key_part+=sort_param.keyinfo->keysegs, sort_param.key++)
    3660                 :   {
    3661               0 :     sort_param.keyinfo=share->keyinfo+sort_param.key;
    3662                 :     /*
    3663                 :       Skip this index if it is marked disabled in the copied
    3664                 :       (and possibly inverted) key_map.
    3665                 :     */
    3666               0 :     if (! maria_is_key_active(key_map, sort_param.key))
    3667                 :     {
    3668                 :       /* Remember old statistics for key */
    3669               0 :       memcpy((char*) rec_per_key_part,
    3670                 :              (char*) (share->state.rec_per_key_part +
    3671                 :                       (uint) (rec_per_key_part - param->new_rec_per_key_part)),
    3672                 :              sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
    3673               0 :       DBUG_PRINT("repair", ("skipping seemingly disabled index #: %u",
    3674                 :                             sort_param.key));
    3675               0 :       continue;
    3676                 :     }
    3677                 : 
    3678               0 :     if ((!(param->testflag & T_SILENT)))
    3679               0 :       printf ("- Fixing index %d\n",sort_param.key+1);
    3680                 : 
    3681               0 :     sort_param.read_cache=param->read_cache;
    3682               0 :     sort_param.seg=sort_param.keyinfo->seg;
    3683               0 :     sort_param.max_pos= sort_param.pos= org_header_length;
    3684               0 :     keyseg=sort_param.seg;
    3685               0 :     bzero((char*) sort_param.unique,sizeof(sort_param.unique));
    3686               0 :     sort_param.key_length=share->rec_reflength;
    3687               0 :     for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++)
    3688                 :     {
    3689               0 :       sort_param.key_length+=keyseg[i].length;
    3690               0 :       if (keyseg[i].flag & HA_SPACE_PACK)
    3691               0 :         sort_param.key_length+=get_pack_length(keyseg[i].length);
    3692               0 :       if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
    3693               0 :         sort_param.key_length+=2 + test(keyseg[i].length >= 127);
    3694               0 :       if (keyseg[i].flag & HA_NULL_PART)
    3695               0 :         sort_param.key_length++;
    3696                 :     }
    3697               0 :     share->state.state.records=share->state.state.del=share->state.split=0;
    3698               0 :     share->state.state.empty=0;
    3699                 : 
    3700               0 :     if (sort_param.keyinfo->flag & HA_FULLTEXT)
    3701                 :     {
    3702                 :       uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
    3703               0 :                                     sort_param.keyinfo->seg->charset->mbmaxlen;
    3704               0 :       sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
    3705                 :       /*
    3706                 :         fulltext indexes may have much more entries than the
    3707                 :         number of rows in the table. We estimate the number here.
    3708                 : 
    3709                 :         Note, built-in parser is always nr. 0 - see ftparser_call_initializer()
    3710                 :       */
    3711               0 :       if (sort_param.keyinfo->ftkey_nr == 0)
    3712                 :       {
    3713                 :         /*
    3714                 :           for built-in parser the number of generated index entries
    3715                 :           cannot be larger than the size of the data file divided
    3716                 :           by the minimal word's length
    3717                 :         */
    3718               0 :         sort_info.max_records=
    3719                 :           (ha_rows) (sort_info.filelength/ft_min_word_len+1);
    3720                 :       }
    3721                 :       else
    3722                 :       {
    3723                 :         /*
    3724                 :           for external plugin parser we cannot tell anything at all :(
    3725                 :           so, we'll use all the sort memory and start from ~10 buffpeks.
    3726                 :           (see _ma_create_index_by_sort)
    3727                 :         */
    3728               0 :         sort_info.max_records=
    3729                 :           10*param->sort_buffer_length/sort_param.key_length;
    3730                 :       }
    3731                 : 
    3732               0 :       sort_param.key_read=  sort_maria_ft_key_read;
    3733               0 :       sort_param.key_write= sort_maria_ft_key_write;
    3734                 :     }
    3735                 :     else
    3736                 :     {
    3737               0 :       sort_param.key_read=  sort_key_read;
    3738               0 :       sort_param.key_write= sort_key_write;
    3739                 :     }
    3740                 : 
    3741               0 :     if (sort_info.new_info->s->data_file_type == BLOCK_RECORD)
    3742                 :     {
    3743               0 :       scan_inited= 1;
    3744               0 :       if (maria_scan_init(sort_info.info))
    3745               0 :         goto err;
    3746                 :     }
    3747               0 :     if (_ma_create_index_by_sort(&sort_param,
    3748                 :                                  (my_bool) (!(param->testflag & T_VERBOSE)),
    3749                 :                                  (size_t) param->sort_buffer_length))
    3750                 :     {
    3751               0 :       param->retry_repair=1;
    3752               0 :       _ma_check_print_error(param, "Create index by sort failed");
    3753               0 :       goto err;
    3754                 :     }
    3755               0 :     DBUG_EXECUTE_IF("maria_flush_whole_log",
    3756                 :                     {
    3757                 :                       DBUG_PRINT("maria_flush_whole_log", ("now"));
    3758                 :                       translog_flush(translog_get_horizon());
    3759                 :                     });
    3760               0 :     DBUG_EXECUTE_IF("maria_crash_create_index_by_sort",
    3761                 :                     {
    3762                 :                       DBUG_PRINT("maria_crash_create_index_by_sort", ("now"));
    3763                 :                       DBUG_ABORT();
    3764                 :                     });
    3765               0 :     if (scan_inited)
    3766                 :     {
    3767               0 :       scan_inited= 0;
    3768               0 :       maria_scan_end(sort_info.info);
    3769                 :     }
    3770                 : 
    3771                 :     /* No need to calculate checksum again. */
    3772               0 :     sort_param.calc_checksum= 0;
    3773               0 :     free_root(&sort_param.wordroot, MYF(0));
    3774                 : 
    3775                 :     /* Set for next loop */
    3776               0 :     sort_info.max_records= (ha_rows) sort_info.new_info->s->state.state.records;
    3777               0 :     if (param->testflag & T_STATISTICS)
    3778               0 :       maria_update_key_parts(sort_param.keyinfo, rec_per_key_part,
    3779                 :                              sort_param.unique,
    3780                 :                              (param->stats_method ==
    3781                 :                               MI_STATS_METHOD_IGNORE_NULLS ?
    3782                 :                               sort_param.notnull : NULL),
    3783                 :                              (ulonglong) share->state.state.records);
    3784               0 :     maria_set_key_active(share->state.key_map, sort_param.key);
    3785               0 :     DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key));
    3786                 : 
    3787               0 :     if (_ma_flush_table_files_before_swap(param, info))
    3788               0 :       goto err;
    3789                 : 
    3790               0 :     if (sort_param.fix_datafile)
    3791                 :     {
    3792               0 :       param->read_cache.end_of_file=sort_param.filepos;
    3793               0 :       if (maria_write_data_suffix(&sort_info,1) ||
    3794                 :           end_io_cache(&sort_info.new_info->rec_cache))
    3795                 :       {
    3796               0 :         _ma_check_print_error(param, "Got error when flushing row cache");
    3797               0 :         goto err;
    3798                 :       }
    3799               0 :       sort_info.new_info->opt_flag&= ~WRITE_CACHE_USED;
    3800                 : 
    3801               0 :       if (param->testflag & T_SAFE_REPAIR)
    3802                 :       {
    3803                 :         /* Don't repair if we loosed more than one row */
    3804               0 :         if (share->state.state.records+1 < start_records)
    3805                 :         {
    3806               0 :           _ma_check_print_error(param,
    3807                 :                                 "Rows lost; Aborting because safe repair was "
    3808                 :                                 "requested");
    3809               0 :           share->state.state.records=start_records;
    3810               0 :           goto err;
    3811                 :         }
    3812                 :       }
    3813                 : 
    3814               0 :       sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
    3815               0 :       if (sort_info.new_info != sort_info.info)
    3816                 :       {
    3817               0 :         MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
    3818               0 :         if (maria_close(sort_info.new_info))
    3819                 :         {
    3820               0 :           _ma_check_print_error(param, "Got error %d on close", my_errno);
    3821               0 :           goto err;
    3822                 :         }
    3823               0 :         copy_data_file_state(&share->state, &save_state);
    3824               0 :         new_file= -1;
    3825               0 :         sort_info.new_info= info;
    3826               0 :         info->rec_cache.file= info->dfile.file;
    3827                 :       }
    3828                 : 
    3829               0 :       share->state.version=(ulong) time((time_t*) 0);        /* Force reopen */
    3830                 : 
    3831                 :       /* Replace the actual file with the temporary file */
    3832               0 :       if (new_file >= 0)
    3833                 :       {
    3834               0 :         my_close(new_file, MYF(MY_WME));
    3835               0 :         new_file= -1;
    3836                 :       }
    3837               0 :       change_data_file_descriptor(info, -1);
    3838               0 :       if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
    3839                 :                                   DATA_TMP_EXT,
    3840                 :                                   (param->testflag & T_BACKUP_DATA ?
    3841                 :                                    MYF(MY_REDEL_MAKE_BACKUP): MYF(0)) |
    3842                 :                                   sync_dir) ||
    3843                 :           _ma_open_datafile(info, share, NullS, -1))
    3844                 :       {
    3845               0 :         _ma_check_print_error(param, "Couldn't change to new data file");
    3846               0 :         goto err;
    3847                 :       }
    3848               0 :       if (param->testflag & T_UNPACK)
    3849               0 :         restore_data_file_type(share);
    3850                 : 
    3851               0 :       org_header_length= share->pack.header_length;
    3852               0 :       sort_info.org_data_file_type= share->data_file_type;
    3853               0 :       sort_info.filelength= share->state.state.data_file_length;
    3854               0 :       sort_param.fix_datafile=0;
    3855                 :     }
    3856                 :     else
    3857               0 :       share->state.state.data_file_length=sort_param.max_pos;
    3858                 : 
    3859               0 :     param->read_cache.file= info->dfile.file;     /* re-init read cache */
    3860               0 :     reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
    3861                 :                     1,1);
    3862                 :   }
    3863                 : 
    3864               0 :   if (param->testflag & T_WRITE_LOOP)
    3865                 :   {
    3866               0 :     VOID(fputs("          \r",stdout)); VOID(fflush(stdout));
    3867                 :   }
    3868                 : 
    3869               0 :   if (rep_quick && del+sort_info.dupp != share->state.state.del)
    3870                 :   {
    3871               0 :     _ma_check_print_error(param,"Couldn't fix table with quick recovery: "
    3872                 :                           "Found wrong number of deleted records");
    3873               0 :     _ma_check_print_error(param,"Run recovery again without -q");
    3874               0 :     got_error=1;
    3875               0 :     param->retry_repair=1;
    3876               0 :     param->testflag|=T_RETRY_WITHOUT_QUICK;
    3877               0 :     goto err;
    3878                 :   }
    3879                 : 
    3880               0 :   if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
    3881                 :   {
    3882                 :     my_off_t skr= (share->state.state.data_file_length +
    3883                 :                    (sort_info.org_data_file_type == COMPRESSED_RECORD) ?
    3884               0 :                    MEMMAP_EXTRA_MARGIN : 0);
    3885                 : #ifdef USE_RELOC
    3886                 :     if (sort_info.org_data_file_type == STATIC_RECORD &&
    3887                 :         skr < share->base.reloc*share->base.min_pack_length)
    3888                 :       skr=share->base.reloc*share->base.min_pack_length;
    3889                 : #endif
    3890               0 :     if (skr != sort_info.filelength)
    3891               0 :       if (my_chsize(info->dfile.file, skr, 0, MYF(0)))
    3892               0 :         _ma_check_print_warning(param,
    3893                 :                                "Can't change size of datafile,  error: %d",
    3894                 :                                my_errno);
    3895                 :   }
    3896                 : 
    3897               0 :   if (param->testflag & T_CALC_CHECKSUM)
    3898               0 :     share->state.state.checksum=param->glob_crc;
    3899                 : 
    3900               0 :   if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0,
    3901                 :                 MYF(0)))
    3902               0 :     _ma_check_print_warning(param,
    3903                 :                            "Can't change size of indexfile, error: %d",
    3904                 :                            my_errno);
    3905                 : 
    3906               0 :   if (!(param->testflag & T_SILENT))
    3907                 :   {
    3908               0 :     if (start_records != share->state.state.records)
    3909               0 :       printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
    3910                 :   }
    3911               0 :   if (sort_info.dupp)
    3912               0 :     _ma_check_print_warning(param,
    3913                 :                             "%s records have been removed",
    3914                 :                             llstr(sort_info.dupp,llbuff));
    3915               0 :   got_error=0;
    3916                 :   /* If invoked by external program that uses thr_lock */
    3917               0 :   if (&share->state.state != info->state)
    3918               0 :     *info->state= *info->state_start= share->state.state;
    3919                 : 
    3920               0 : err:
    3921               0 :   if (scan_inited)
    3922               0 :     maria_scan_end(sort_info.info);
    3923               0 :   _ma_reset_state(info);
    3924                 : 
    3925               0 :   VOID(end_io_cache(&sort_info.new_info->rec_cache));
    3926               0 :   VOID(end_io_cache(&param->read_cache));
    3927               0 :   info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
    3928               0 :   sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
    3929               0 :   if (got_error)
    3930                 :   {
    3931               0 :     if (! param->error_printed)
    3932               0 :       _ma_check_print_error(param,"%d when fixing table",my_errno);
    3933               0 :     (void)_ma_flush_table_files_before_swap(param, info);
    3934               0 :     if (sort_info.new_info && sort_info.new_info != sort_info.info)
    3935                 :     {
    3936               0 :       unuse_data_file_descriptor(sort_info.new_info);
    3937               0 :       maria_close(sort_info.new_info);
    3938                 :     }
    3939               0 :     if (new_file >= 0)
    3940                 :     {
    3941               0 :       VOID(my_close(new_file,MYF(0)));
    3942               0 :       VOID(my_delete(param->temp_filename, MYF(MY_WME)));
    3943                 :     }
    3944               0 :     maria_mark_crashed_on_repair(info);
    3945                 :   }
    3946                 :   else
    3947                 :   {
    3948               0 :     if (key_map == share->state.key_map)
    3949               0 :       share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
    3950                 :     /*
    3951                 :       Now that we have flushed and forced everything, we can bump
    3952                 :       create_rename_lsn:
    3953                 :     */
    3954               0 :     DBUG_EXECUTE_IF("maria_flush_whole_log",
    3955                 :                     {
    3956                 :                       DBUG_PRINT("maria_flush_whole_log", ("now"));
    3957                 :                       translog_flush(translog_get_horizon());
    3958                 :                     });
    3959               0 :     DBUG_EXECUTE_IF("maria_crash_repair",
    3960                 :                     {
    3961                 :                       DBUG_PRINT("maria_crash_repair", ("now"));
    3962                 :                       DBUG_ABORT();
    3963                 :                     });
    3964                 :   }
    3965               0 :   share->state.changed|= STATE_NOT_SORTED_PAGES;
    3966               0 :   if (!rep_quick)
    3967               0 :     share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
    3968                 :                              STATE_NOT_MOVABLE);
    3969                 : 
    3970               0 :   my_free(sort_param.rec_buff, MYF(MY_ALLOW_ZERO_PTR));
    3971               0 :   my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
    3972               0 :   my_free(sort_info.key_block, MYF(MY_ALLOW_ZERO_PTR));
    3973               0 :   my_free(sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR));
    3974               0 :   my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
    3975               0 :   DBUG_RETURN(got_error);
    3976                 : }
    3977                 : 
    3978                 : 
    3979                 : /*
    3980                 :   Threaded repair of table using sorting
    3981                 : 
    3982                 :   SYNOPSIS
    3983                 :     maria_repair_parallel()
    3984                 :     param               Repair parameters
    3985                 :     info                MARIA handler to repair
    3986                 :     name                Name of table (for warnings)
    3987                 :     rep_quick           set to <> 0 if we should not change data file
    3988                 : 
    3989                 :   DESCRIPTION
    3990                 :     Same as maria_repair_by_sort but do it multithreaded
    3991                 :     Each key is handled by a separate thread.
    3992                 :     TODO: make a number of threads a parameter
    3993                 : 
    3994                 :     In parallel repair we use one thread per index. There are two modes:
    3995                 : 
    3996                 :     Quick
    3997                 : 
    3998                 :       Only the indexes are rebuilt. All threads share a read buffer.
    3999                 :       Every thread that needs fresh data in the buffer enters the shared
    4000                 :       cache lock. The last thread joining the lock reads the buffer from
    4001                 :       the data file and wakes all other threads.
    4002                 : 
    4003                 :     Non-quick
    4004                 : 
    4005                 :       The data file is rebuilt and all indexes are rebuilt to point to
    4006                 :       the new record positions. One thread is the master thread. It
    4007                 :       reads from the old data file and writes to the new data file. It
    4008                 :       also creates one of the indexes. The other threads read from a
    4009                 :       buffer which is filled by the master. If they need fresh data,
    4010                 :       they enter the shared cache lock. If the masters write buffer is
    4011                 :       full, it flushes it to the new data file and enters the shared
    4012                 :       cache lock too. When all threads joined in the lock, the master
    4013                 :       copies its write buffer to the read buffer for the other threads
    4014                 :       and wakes them.
    4015                 : 
    4016                 :   RESULT
    4017                 :     0   ok
    4018                 :     <>0   Error
    4019                 : */
    4020                 : 
    4021                 : int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
    4022                 :                         const char * name, my_bool rep_quick)
    4023               0 : {
    4024                 : #ifndef THREAD
    4025                 :   return maria_repair_by_sort(param, info, name, rep_quick);
    4026                 : #else
    4027                 :   int got_error;
    4028                 :   uint i,key, total_key_length, istep;
    4029                 :   ha_rows start_records;
    4030                 :   my_off_t new_header_length,del;
    4031                 :   File new_file;
    4032               0 :   MARIA_SORT_PARAM *sort_param=0, tmp_sort_param;
    4033               0 :   MARIA_SHARE *share= info->s;
    4034                 :   double  *rec_per_key_part;
    4035                 :   HA_KEYSEG *keyseg;
    4036                 :   char llbuff[22];
    4037                 :   IO_CACHE new_data_cache; /* For non-quick repair. */
    4038                 :   IO_CACHE_SHARE io_share;
    4039                 :   MARIA_SORT_INFO sort_info;
    4040                 :   ulonglong key_map;
    4041                 :   pthread_attr_t thr_attr;
    4042                 :   myf sync_dir= ((share->now_transactional && !share->temporary) ?
    4043               0 :                  MY_SYNC_DIR : 0);
    4044               0 :   DBUG_ENTER("maria_repair_parallel");
    4045               0 :   LINT_INIT(key_map);
    4046                 : 
    4047               0 :   got_error= 1;
    4048               0 :   new_file= -1;
    4049               0 :   start_records= share->state.state.records;
    4050               0 :   if (!(param->testflag & T_SILENT))
    4051                 :   {
    4052               0 :     printf("- parallel recovering (with sort) MARIA-table '%s'\n",name);
    4053               0 :     printf("Data records: %s\n", llstr(start_records, llbuff));
    4054                 :   }
    4055                 : 
    4056               0 :   if (initialize_variables_for_repair(param, &sort_info, &tmp_sort_param, info,
    4057                 :                                       rep_quick))
    4058               0 :     goto err;
    4059                 : 
    4060               0 :   new_header_length= ((param->testflag & T_UNPACK) ? 0 :
    4061                 :                       share->pack.header_length);
    4062                 : 
    4063                 :   /*
    4064                 :     Quick repair (not touching data file, rebuilding indexes):
    4065                 :     {
    4066                 :       Read cache is (HA_CHECK *param)->read_cache using info->dfile.file.
    4067                 :     }
    4068                 : 
    4069                 :     Non-quick repair (rebuilding data file and indexes):
    4070                 :     {
    4071                 :       Master thread:
    4072                 : 
    4073                 :         Read  cache is (HA_CHECK *param)->read_cache using info->dfile.file.
    4074                 :         Write cache is (MARIA_INFO *info)->rec_cache using new_file.
    4075                 : 
    4076                 :       Slave threads:
    4077                 : 
    4078                 :         Read cache is new_data_cache synced to master rec_cache.
    4079                 : 
    4080                 :       The final assignment of the filedescriptor for rec_cache is done
    4081                 :       after the cache creation.
    4082                 : 
    4083                 :       Don't check file size on new_data_cache, as the resulting file size
    4084                 :       is not known yet.
    4085                 : 
    4086                 :       As rec_cache and new_data_cache are synced, write_buffer_length is
    4087                 :       used for the read cache 'new_data_cache'. Both start at the same
    4088                 :       position 'new_header_length'.
    4089                 :     }
    4090                 :   */
    4091               0 :   DBUG_PRINT("info", ("is quick repair: %d", (int) rep_quick));
    4092                 : 
    4093                 :   /* Initialize pthread structures before goto err. */
    4094               0 :   pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
    4095               0 :   pthread_cond_init(&sort_info.cond, 0);
    4096                 : 
    4097               0 :   if (!(sort_info.key_block=
    4098                 :         alloc_key_blocks(param, (uint) param->sort_key_blocks,
    4099                 :                          share->base.max_key_block_length)) ||
    4100                 :       init_io_cache(&param->read_cache, info->dfile.file,
    4101                 :                     (uint) param->read_buffer_length,
    4102                 :                     READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) ||
    4103                 :       (!rep_quick &&
    4104                 :        (init_io_cache(&info->rec_cache, info->dfile.file,
    4105                 :                       (uint) param->write_buffer_length,
    4106                 :                       WRITE_CACHE, new_header_length, 1,
    4107                 :                       MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) ||
    4108                 :         init_io_cache(&new_data_cache, -1,
    4109                 :                       (uint) param->write_buffer_length,
    4110                 :                       READ_CACHE, new_header_length, 1,
    4111                 :                       MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))))
    4112                 :     goto err;
    4113               0 :   sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
    4114               0 :   info->opt_flag|=WRITE_CACHE_USED;
    4115               0 :   info->rec_cache.file= info->dfile.file;         /* for sort_delete_record */
    4116                 : 
    4117               0 :   if (!rep_quick)
    4118                 :   {
    4119                 :     /* Get real path for data file */
    4120               0 :     if ((new_file= my_create(fn_format(param->temp_filename,
    4121                 :                                        share->data_file_name.str, "",
    4122                 :                                        DATA_TMP_EXT,
    4123                 :                                        2+4),
    4124                 :                              0,param->tmpfile_createflag,
    4125                 :                              MYF(0))) < 0)
    4126                 :     {
    4127               0 :       _ma_check_print_error(param,"Can't create new tempfile: '%s'",
    4128                 :                            param->temp_filename);
    4129               0 :       goto err;
    4130                 :     }
    4131               0 :     if (new_header_length &&
    4132                 :         maria_filecopy(param, new_file, info->dfile.file,0L,new_header_length,
    4133                 :                        "datafile-header"))
    4134               0 :       goto err;
    4135               0 :     if (param->testflag & T_UNPACK)
    4136               0 :       restore_data_file_type(share);
    4137               0 :     share->state.dellink= HA_OFFSET_ERROR;
    4138               0 :     info->rec_cache.file=new_file;
    4139                 :   }
    4140                 : 
    4141                 :   /* Optionally drop indexes and optionally modify the key_map. */
    4142               0 :   maria_drop_all_indexes(param, info, FALSE);
    4143               0 :   key_map= share->state.key_map;
    4144               0 :   if (param->testflag & T_CREATE_MISSING_KEYS)
    4145                 :   {
    4146                 :     /* Invert the copied key_map to recreate all disabled indexes. */
    4147               0 :     key_map= ~key_map;
    4148                 :   }
    4149                 : 
    4150               0 :   param->read_cache.end_of_file= sort_info.filelength;
    4151                 : 
    4152                 :   /*
    4153                 :     +1 below is required hack for parallel repair mode.
    4154                 :     The share->state.state.records value, that is compared later
    4155                 :     to sort_info.max_records and cannot exceed it, is
    4156                 :     increased in sort_key_write. In maria_repair_by_sort, sort_key_write
    4157                 :     is called after sort_key_read, where the comparison is performed,
    4158                 :     but in parallel mode master thread can call sort_key_write
    4159                 :     before some other repair thread calls sort_key_read.
    4160                 :     Furthermore I'm not even sure +1 would be enough.
    4161                 :     May be sort_info.max_records shold be always set to max value in
    4162                 :     parallel mode.
    4163                 :   */
    4164               0 :   sort_info.max_records++;
    4165                 : 
    4166               0 :   del=share->state.state.del;
    4167                 : 
    4168               0 :   if (!(sort_param=(MARIA_SORT_PARAM *)
    4169                 :         my_malloc((uint) share->base.keys *
    4170                 :                   (sizeof(MARIA_SORT_PARAM) + share->base.pack_reclength),
    4171                 :                   MYF(MY_ZEROFILL))))
    4172                 :   {
    4173               0 :     _ma_check_print_error(param,"Not enough memory for key!");
    4174               0 :     goto err;
    4175                 :   }
    4176               0 :   total_key_length=0;
    4177               0 :   rec_per_key_part= param->new_rec_per_key_part;
    4178               0 :   share->state.state.records=share->state.state.del=share->state.split=0;
    4179               0 :   share->state.state.empty=0;
    4180                 : 
    4181               0 :   for (i=key=0, istep=1 ; key < share->base.keys ;
    4182               0 :        rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
    4183                 :   {
    4184               0 :     sort_param[i].key=key;
    4185               0 :     sort_param[i].keyinfo=share->keyinfo+key;
    4186               0 :     sort_param[i].seg=sort_param[i].keyinfo->seg;
    4187                 :     /*
    4188                 :       Skip this index if it is marked disabled in the copied
    4189                 :       (and possibly inverted) key_map.
    4190                 :     */
    4191               0 :     if (! maria_is_key_active(key_map, key))
    4192                 :     {
    4193                 :       /* Remember old statistics for key */
    4194               0 :       memcpy((char*) rec_per_key_part,
    4195                 :              (char*) (share->state.rec_per_key_part+
    4196                 :                       (uint) (rec_per_key_part - param->new_rec_per_key_part)),
    4197                 :              sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
    4198               0 :       istep=0;
    4199               0 :       continue;
    4200                 :     }
    4201               0 :     istep=1;
    4202               0 :     if ((!(param->testflag & T_SILENT)))
    4203               0 :       printf ("- Fixing index %d\n",key+1);
    4204               0 :     if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
    4205                 :     {
    4206               0 :       sort_param[i].key_read=sort_maria_ft_key_read;
    4207               0 :       sort_param[i].key_write=sort_maria_ft_key_write;
    4208                 :     }
    4209                 :     else
    4210                 :     {
    4211               0 :       sort_param[i].key_read=sort_key_read;
    4212               0 :       sort_param[i].key_write=sort_key_write;
    4213                 :     }
    4214               0 :     sort_param[i].key_cmp=sort_key_cmp;
    4215               0 :     sort_param[i].lock_in_memory=maria_lock_memory;
    4216               0 :     sort_param[i].tmpdir=param->tmpdir;
    4217               0 :     sort_param[i].sort_info=&sort_info;
    4218               0 :     sort_param[i].master=0;
    4219               0 :     sort_param[i].fix_datafile=0;
    4220               0 :     sort_param[i].calc_checksum= 0;
    4221                 : 
    4222               0 :     sort_param[i].filepos=new_header_length;
    4223               0 :     sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
    4224                 : 
    4225               0 :     sort_param[i].record= (((uchar *)(sort_param+share->base.keys))+
    4226                 :                           (share->base.pack_reclength * i));
    4227               0 :     if (_ma_alloc_buffer(&sort_param[i].rec_buff, &sort_param[i].rec_buff_size,
    4228                 :                          share->base.default_rec_buff_size))
    4229                 :     {
    4230               0 :       _ma_check_print_error(param,"Not enough memory!");
    4231               0 :       goto err;
    4232                 :     }
    4233               0 :     sort_param[i].key_length=share->rec_reflength;
    4234               0 :     for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END;
    4235               0 :          keyseg++)
    4236                 :     {
    4237               0 :       sort_param[i].key_length+=keyseg->length;
    4238               0 :       if (keyseg->flag & HA_SPACE_PACK)
    4239               0 :         sort_param[i].key_length+=get_pack_length(keyseg->length);
    4240               0 :       if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
    4241               0 :         sort_param[i].key_length+=2 + test(keyseg->length >= 127);
    4242               0 :       if (keyseg->flag & HA_NULL_PART)
    4243               0 :         sort_param[i].key_length++;
    4244                 :     }
    4245               0 :     total_key_length+=sort_param[i].key_length;
    4246                 : 
    4247               0 :     if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
    4248                 :     {
    4249                 :       uint ft_max_word_len_for_sort=
    4250                 :         (FT_MAX_WORD_LEN_FOR_SORT *
    4251               0 :          sort_param[i].keyinfo->seg->charset->mbmaxlen);
    4252               0 :       sort_param[i].key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
    4253               0 :       init_alloc_root(&sort_param[i].wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
    4254                 :     }
    4255                 :   }
    4256               0 :   sort_info.total_keys=i;
    4257               0 :   sort_param[0].master= 1;
    4258               0 :   sort_param[0].fix_datafile= ! rep_quick;
    4259               0 :   sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
    4260                 : 
    4261               0 :   if (!maria_ftparser_alloc_param(info))
    4262               0 :     goto err;
    4263                 : 
    4264               0 :   sort_info.got_error=0;
    4265               0 :   pthread_mutex_lock(&sort_info.mutex);
    4266                 : 
    4267                 :   /*
    4268                 :     Initialize the I/O cache share for use with the read caches and, in
    4269                 :     case of non-quick repair, the write cache. When all threads join on
    4270                 :     the cache lock, the writer copies the write cache contents to the
    4271                 :     read caches.
    4272                 :   */
    4273               0 :   if (i > 1)
    4274                 :   {
    4275               0 :     if (rep_quick)
    4276               0 :       init_io_cache_share(&param->read_cache, &io_share, NULL, i);
    4277                 :     else
    4278               0 :       init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i);
    4279                 :   }
    4280                 :   else
    4281               0 :     io_share.total_threads= 0; /* share not used */
    4282                 : 
    4283               0 :   (void) pthread_attr_init(&thr_attr);
    4284               0 :   (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
    4285                 : 
    4286               0 :   for (i=0 ; i < sort_info.total_keys ; i++)
    4287                 :   {
    4288                 :     /*
    4289                 :       Copy the properly initialized IO_CACHE structure so that every
    4290                 :       thread has its own copy. In quick mode param->read_cache is shared
    4291                 :       for use by all threads. In non-quick mode all threads but the
    4292                 :       first copy the shared new_data_cache, which is synchronized to the
    4293                 :       write cache of the first thread. The first thread copies
    4294                 :       param->read_cache, which is not shared.
    4295                 :     */
    4296               0 :     sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache :
    4297                 :                                new_data_cache);
    4298               0 :     DBUG_PRINT("io_cache_share", ("thread: %u  read_cache: 0x%lx",
    4299                 :                                   i, (long) &sort_param[i].read_cache));
    4300                 : 
    4301                 :     /*
    4302                 :       two approaches: the same amount of memory for each thread
    4303                 :       or the memory for the same number of keys for each thread...
    4304                 :       In the second one all the threads will fill their sort_buffers
    4305                 :       (and call write_keys) at the same time, putting more stress on i/o.
    4306                 :     */
    4307               0 :     sort_param[i].sortbuff_size=
    4308                 : #ifndef USING_SECOND_APPROACH
    4309                 :       param->sort_buffer_length/sort_info.total_keys;
    4310                 : #else
    4311                 :       param->sort_buffer_length*sort_param[i].key_length/total_key_length;
    4312                 : #endif
    4313               0 :     if (pthread_create(&sort_param[i].thr, &thr_attr,
    4314                 :                        _ma_thr_find_all_keys,
    4315                 :                        (void *) (sort_param+i)))
    4316                 :     {
    4317               0 :       _ma_check_print_error(param,"Cannot start a repair thread");
    4318                 :       /* Cleanup: Detach from the share. Avoid others to be blocked. */
    4319               0 :       if (io_share.total_threads)
    4320               0 :         remove_io_thread(&sort_param[i].read_cache);
    4321               0 :       DBUG_PRINT("error", ("Cannot start a repair thread"));
    4322               0 :       sort_info.got_error=1;
    4323                 :     }
    4324                 :     else
    4325               0 :       sort_info.threads_running++;
    4326                 :   }
    4327               0 :   (void) pthread_attr_destroy(&thr_attr);
    4328                 : 
    4329                 :   /* waiting for all threads to finish */
    4330               0 :   while (sort_info.threads_running)
    4331               0 :     pthread_cond_wait(&sort_info.cond, &sort_info.mutex);
    4332               0 :   pthread_mutex_unlock(&sort_info.mutex);
    4333                 : 
    4334               0 :   if ((got_error= _ma_thr_write_keys(sort_param)))
    4335                 :   {
    4336               0 :     param->retry_repair=1;
    4337               0 :     goto err;
    4338                 :   }
    4339               0 :   got_error=1;                          /* Assume the following may go wrong */
    4340                 : 
    4341               0 :   if (_ma_flush_table_files_before_swap(param, info))
    4342               0 :     goto err;
    4343                 : 
    4344               0 :   if (sort_param[0].fix_datafile)
    4345                 :   {
    4346                 :     /*
    4347                 :       Append some nulls to the end of a memory mapped file. Destroy the
    4348                 :       write cache. The master thread did already detach from the share
    4349                 :       by remove_io_thread() in sort.c:thr_find_all_keys().
    4350                 :     */
    4351               0 :     if (maria_write_data_suffix(&sort_info,1) ||
    4352                 :         end_io_cache(&info->rec_cache))
    4353                 :       goto err;
    4354               0 :     if (param->testflag & T_SAFE_REPAIR)
    4355                 :     {
    4356                 :       /* Don't repair if we loosed more than one row */
    4357               0 :       if (share->state.state.records+1 < start_records)
    4358                 :       {
    4359               0 :         share->state.state.records=start_records;
    4360               0 :         goto err;
    4361                 :       }
    4362                 :     }
    4363               0 :     share->state.state.data_file_length= share->state.state.data_file_length=
    4364                 :       sort_param->filepos;
    4365                 :     /* Only whole records */
    4366               0 :     share->state.version= (ulong) time((time_t*) 0);
    4367                 :     /*
    4368                 :       Exchange the data file descriptor of the table, so that we use the
    4369                 :       new file from now on.
    4370                 :      */
    4371               0 :     my_close(info->dfile.file, MYF(0));
    4372               0 :     info->dfile.file= new_file;
    4373               0 :     share->pack.header_length=(ulong) new_header_length;
    4374                 :   }
    4375                 :   else
    4376               0 :     share->state.state.data_file_length=sort_param->max_pos;
    4377                 : 
    4378               0 :   if (rep_quick && del+sort_info.dupp != share->state.state.del)
    4379                 :   {
    4380               0 :     _ma_check_print_error(param,"Couldn't fix table with quick recovery: "
    4381                 :                           "Found wrong number of deleted records");
    4382               0 :     _ma_check_print_error(param,"Run recovery again without -q");
    4383               0 :     param->retry_repair=1;
    4384               0 :     param->testflag|=T_RETRY_WITHOUT_QUICK;
    4385               0 :     goto err;
    4386                 :   }
    4387                 : 
    4388               0 :   if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
    4389                 :   {
    4390                 :     my_off_t skr= (share->state.state.data_file_length +
    4391                 :                    (sort_info.org_data_file_type == COMPRESSED_RECORD) ?
    4392               0 :                    MEMMAP_EXTRA_MARGIN : 0);
    4393                 : #ifdef USE_RELOC
    4394                 :     if (sort_info.org_data_file_type == STATIC_RECORD &&
    4395                 :         skr < share->base.reloc*share->base.min_pack_length)
    4396                 :       skr=share->base.reloc*share->base.min_pack_length;
    4397                 : #endif
    4398               0 :     if (skr != sort_info.filelength)
    4399               0 :       if (my_chsize(info->dfile.file, skr, 0, MYF(0)))
    4400               0 :         _ma_check_print_warning(param,
    4401                 :                                "Can't change size of datafile,  error: %d",
    4402                 :                                my_errno);
    4403                 :   }
    4404               0 :   if (param->testflag & T_CALC_CHECKSUM)
    4405               0 :     share->state.state.checksum=param->glob_crc;
    4406                 : 
    4407               0 :   if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0,
    4408                 :                 MYF(0)))
    4409               0 :     _ma_check_print_warning(param,
    4410                 :                            "Can't change size of indexfile, error: %d",
    4411                 :                             my_errno);
    4412                 : 
    4413               0 :   if (!(param->testflag & T_SILENT))
    4414                 :   {
    4415               0 :     if (start_records != share->state.state.records)
    4416               0 :       printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
    4417                 :   }
    4418               0 :   if (sort_info.dupp)
    4419               0 :     _ma_check_print_warning(param,
    4420                 :                             "%s records have been removed",
    4421                 :                             llstr(sort_info.dupp,llbuff));
    4422               0 :   got_error=0;
    4423                 :   /* If invoked by external program that uses thr_lock */
    4424               0 :   if (&share->state.state != info->state)
    4425               0 :     *info->state= *info->state_start= share->state.state;
    4426                 : 
    4427               0 : err:
    4428               0 :   _ma_reset_state(info);
    4429                 : 
    4430                 :   /*
    4431                 :     Destroy the write cache. The master thread did already detach from
    4432                 :     the share by remove_io_thread() or it was not yet started (if the
    4433                 :     error happend before creating the thread).
    4434                 :   */
    4435               0 :   VOID(end_io_cache(&sort_info.new_info->rec_cache));
    4436               0 :   VOID(end_io_cache(&param->read_cache));
    4437               0 :   info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
    4438               0 :   sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
    4439                 :   /*
    4440                 :     Destroy the new data cache in case of non-quick repair. All slave
    4441                 :     threads did either detach from the share by remove_io_thread()
    4442                 :     already or they were not yet started (if the error happend before
    4443                 :     creating the threads).
    4444                 :   */
    4445               0 :   if (!rep_quick)
    4446               0 :     VOID(end_io_cache(&new_data_cache));
    4447               0 :   if (!got_error)
    4448                 :   {
    4449                 :     /* Replace the actual file with the temporary file */
    4450               0 :     if (new_file >= 0)
    4451                 :     {
    4452               0 :       my_close(new_file,MYF(0));
    4453               0 :       info->dfile.file= new_file= -1;
    4454               0 :       if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
    4455                 :                                   DATA_TMP_EXT,
    4456                 :                                   MYF((param->testflag & T_BACKUP_DATA ?
    4457                 :                                        MY_REDEL_MAKE_BACKUP : 0) |
    4458                 :                                       sync_dir)) ||
    4459                 :           _ma_open_datafile(info,share, NullS, -1))
    4460               0 :         got_error=1;
    4461                 :     }
    4462                 :   }
    4463               0 :   if (got_error)
    4464                 :   {
    4465               0 :     if (! param->error_printed)
    4466               0 :       _ma_check_print_error(param,"%d when fixing table",my_errno);
    4467               0 :     (void)_ma_flush_table_files_before_swap(param, info);
    4468               0 :     if (new_file >= 0)
    4469                 :     {
    4470               0 :       VOID(my_close(new_file,MYF(0)));
    4471               0 :       VOID(my_delete(param->temp_filename, MYF(MY_WME)));
    4472               0 :       if (info->dfile.file == new_file)
    4473               0 :         info->dfile.file= -1;
    4474                 :     }
    4475               0 :     maria_mark_crashed_on_repair(info);
    4476                 :   }
    4477               0 :   else if (key_map == share->state.key_map)
    4478               0 :     share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
    4479               0 :   share->state.changed|= STATE_NOT_SORTED_PAGES;
    4480               0 :   if (!rep_quick)
    4481               0 :     share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
    4482                 :                              STATE_NOT_MOVABLE);
    4483                 : 
    4484               0 :   pthread_cond_destroy (&sort_info.cond);
    4485               0 :   pthread_mutex_destroy(&sort_info.mutex);
    4486                 : 
    4487               0 :   my_free(sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR));
    4488               0 :   my_free(sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
    4489               0 :   my_free(sort_param,MYF(MY_ALLOW_ZERO_PTR));
    4490               0 :   my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
    4491               0 :   if (!got_error && (param->testflag & T_UNPACK))
    4492               0 :     restore_data_file_type(share);
    4493               0 :   DBUG_RETURN(got_error);
    4494                 : #endif /* THREAD */
    4495                 : }
    4496                 : 
    4497                 :         /* Read next record and return next key */
    4498                 : 
    4499                 : static int sort_key_read(MARIA_SORT_PARAM *sort_param, uchar *key)
    4500               0 : {
    4501                 :   int error;
    4502               0 :   MARIA_SORT_INFO *sort_info= sort_param->sort_info;
    4503               0 :   MARIA_HA *info= sort_info->info;
    4504                 :   MARIA_KEY int_key;
    4505               0 :   DBUG_ENTER("sort_key_read");
    4506                 : 
    4507               0 :   if ((error=sort_get_next_record(sort_param)))
    4508               0 :     DBUG_RETURN(error);
    4509               0 :   if (info->s->state.state.records == sort_info->max_records)
    4510                 :   {
    4511               0 :     _ma_check_print_error(sort_info->param,
    4512                 :                          "Key %d - Found too many records; Can't continue",
    4513                 :                          sort_param->key+1);
    4514               0 :     DBUG_RETURN(1);
    4515                 :   }
    4516               0 :   if (_ma_sort_write_record(sort_param))
    4517               0 :     DBUG_RETURN(1);
    4518                 : 
    4519               0 :   (*info->s->keyinfo[sort_param->key].make_key)(info, &int_key,
    4520                 :                                                 sort_param->key, key,
    4521                 :                                                 sort_param->record,
    4522                 :                                                 sort_param->current_filepos,
    4523                 :                                                 0);
    4524               0 :   sort_param->real_key_length= int_key.data_length + int_key.ref_length;
    4525                 : #ifdef HAVE_purify
    4526                 :   bzero(key+sort_param->real_key_length,
    4527                 :         (sort_param->key_length-sort_param->real_key_length));
    4528                 : #endif
    4529               0 :   DBUG_RETURN(0);
    4530                 : } /* sort_key_read */
    4531                 : 
    4532                 : 
    4533                 : static int sort_maria_ft_key_read(MARIA_SORT_PARAM *sort_param, uchar *key)
    4534               0 : {
    4535                 :   int error;
    4536               0 :   MARIA_SORT_INFO *sort_info=sort_param->sort_info;
    4537               0 :   MARIA_HA *info=sort_info->info;
    4538               0 :   FT_WORD *wptr=0;
    4539                 :   MARIA_KEY int_key;
    4540               0 :   DBUG_ENTER("sort_maria_ft_key_read");
    4541                 : 
    4542               0 :   if (!sort_param->wordlist)
    4543                 :   {
    4544                 :     for (;;)
    4545                 :     {
    4546               0 :       free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
    4547               0 :       if ((error=sort_get_next_record(sort_param)))
    4548               0 :         DBUG_RETURN(error);
    4549               0 :       if ((error= _ma_sort_write_record(sort_param)))
    4550               0 :         DBUG_RETURN(error);
    4551               0 :       if (!(wptr= _ma_ft_parserecord(info,sort_param->key,sort_param->record,
    4552                 :                                      &sort_param->wordroot)))
    4553                 : 
    4554               0 :         DBUG_RETURN(1);
    4555               0 :       if (wptr->pos)
    4556                 :         break;
    4557                 :     }
    4558               0 :     sort_param->wordptr=sort_param->wordlist=wptr;
    4559                 :   }
    4560                 :   else
    4561                 :   {
    4562               0 :     error=0;
    4563               0 :     wptr=(FT_WORD*)(sort_param->wordptr);
    4564                 :   }
    4565                 : 
    4566               0 :   _ma_ft_make_key(info, &int_key, sort_param->key, key, wptr++,
    4567                 :                   sort_param->current_filepos);
    4568               0 :   sort_param->real_key_length= int_key.data_length + int_key.ref_length;
    4569                 : 
    4570                 : #ifdef HAVE_purify
    4571                 :   if (sort_param->key_length > sort_param->real_key_length)
    4572                 :     bzero(key+sort_param->real_key_length,
    4573                 :           (sort_param->key_length-sort_param->real_key_length));
    4574                 : #endif
    4575               0 :   if (!wptr->pos)
    4576                 :   {
    4577               0 :     free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
    4578               0 :     sort_param->wordlist=0;
    4579                 :   }
    4580                 :   else
    4581               0 :     sort_param->wordptr=(void*)wptr;
    4582                 : 
    4583               0 :   DBUG_RETURN(error);
    4584                 : } /* sort_maria_ft_key_read */
    4585                 : 
    4586                 : 
    4587                 : /*
    4588                 :   Read next record from file using parameters in sort_info.
    4589                 : 
    4590                 :   SYNOPSIS
    4591                 :     sort_get_next_record()
    4592                 :       sort_param                Information about and for the sort process
    4593                 : 
    4594                 :   NOTES
    4595                 :     Dynamic Records With Non-Quick Parallel Repair
    4596                 : 
    4597                 :     For non-quick parallel repair we use a synchronized read/write
    4598                 :     cache. This means that one thread is the master who fixes the data
    4599                 :     file by reading each record from the old data file and writing it
    4600                 :     to the new data file. By doing this the records in the new data
    4601                 :     file are written contiguously. Whenever the write buffer is full,
    4602                 :     it is copied to the read buffer. The slaves read from the read
    4603                 :     buffer, which is not associated with a file. Thus read_cache.file
    4604                 :     is -1. When using _mi_read_cache(), the slaves must always set
    4605                 :     flag to READING_NEXT so that the function never tries to read from
    4606                 :     file. This is safe because the records are contiguous. There is no
    4607                 :     need to read outside the cache. This condition is evaluated in the
    4608                 :     variable 'parallel_flag' for quick reference. read_cache.file must
    4609                 :     be >= 0 in every other case.
    4610                 : 
    4611                 :   RETURN
    4612                 :     -1          end of file
    4613                 :     0           ok
    4614                 :                 sort_param->current_filepos points to record position.
    4615                 :                 sort_param->record contains record
    4616                 :                 sort_param->max_pos contains position to last byte read
    4617                 :     > 0         error
    4618                 : */
    4619                 : 
    4620                 : static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
    4621               0 : {
    4622                 :   int searching;
    4623                 :   int parallel_flag;
    4624                 :   uint found_record,b_type,left_length;
    4625                 :   my_off_t pos;
    4626                 :   MARIA_BLOCK_INFO block_info;
    4627               0 :   MARIA_SORT_INFO *sort_info=sort_param->sort_info;
    4628               0 :   HA_CHECK *param=sort_info->param;
    4629               0 :   MARIA_HA *info=sort_info->info;
    4630               0 :   MARIA_SHARE *share= info->s;
    4631                 :   char llbuff[22],llbuff2[22];
    4632               0 :   DBUG_ENTER("sort_get_next_record");
    4633                 : 
    4634               0 :   if (*_ma_killed_ptr(param))
    4635               0 :     DBUG_RETURN(1);
    4636                 : 
    4637               0 :   switch (sort_info->org_data_file_type) {
    4638                 :   case BLOCK_RECORD:
    4639                 :   {
    4640                 :     for (;;)
    4641                 :     {
    4642                 :       int flag;
    4643                 :       /*
    4644                 :         Assume table is transactional and it had LSN pages in the
    4645                 :         cache. Repair has flushed them, left data pages stay in
    4646                 :         cache, and disabled transactionality (so share's current page
    4647                 :         type is PLAIN); page cache would assert if it finds a cached LSN page
    4648                 :         while _ma_scan_block_record() requested a PLAIN page. So we use
    4649                 :         UNKNOWN.
    4650                 :       */
    4651               0 :       enum pagecache_page_type save_page_type= share->page_type;
    4652               0 :       share->page_type= PAGECACHE_READ_UNKNOWN_PAGE;
    4653               0 :       if (info != sort_info->new_info)
    4654                 :       {
    4655                 :         /* Safe scanning */
    4656               0 :         flag= _ma_safe_scan_block_record(sort_info, info,
    4657                 :                                          sort_param->record);
    4658                 :       }
    4659                 :       else
    4660                 :       {
    4661                 :         /*
    4662                 :           Scan on clean table.
    4663                 :           It requires a reliable data_file_length so we set it.
    4664                 :         */
    4665               0 :         share->state.state.data_file_length= sort_info->filelength;
    4666               0 :         info->cur_row.trid= 0;
    4667               0 :         flag= _ma_scan_block_record(info, sort_param->record,
    4668                 :                                     info->cur_row.nextpos, 1);
    4669               0 :         set_if_bigger(param->max_found_trid, info->cur_row.trid);
    4670               0 :         if (info->cur_row.trid > param->max_trid)
    4671                 :         {
    4672               0 :           _ma_check_print_not_visible_error(param, info->cur_row.trid);
    4673               0 :           flag= HA_ERR_ROW_NOT_VISIBLE;
    4674                 :         }
    4675                 :       }
    4676               0 :       share->page_type= save_page_type;
    4677               0 :       if (!flag)
    4678                 :       {
    4679               0 :         if (sort_param->calc_checksum)
    4680                 :         {
    4681                 :           ha_checksum checksum;
    4682               0 :           checksum= (*share->calc_check_checksum)(info, sort_param->record);
    4683               0 :           if (share->calc_checksum &&
    4684                 :               info->cur_row.checksum != (checksum & 255))
    4685                 :           {
    4686               0 :             if (param->testflag & T_VERBOSE)
    4687                 :             {
    4688               0 :               record_pos_to_txt(info, info->cur_row.lastpos, llbuff);
    4689               0 :               _ma_check_print_info(param,
    4690                 :                                    "Found record with wrong checksum at %s",
    4691                 :                                    llbuff);
    4692                 :             }
    4693                 :             continue;
    4694                 :           }
    4695               0 :           info->cur_row.checksum= checksum;
    4696               0 :           param->glob_crc+= checksum;
    4697                 :         }
    4698               0 :         sort_param->start_recpos= sort_param->current_filepos=
    4699                 :           info->cur_row.lastpos;
    4700               0 :         DBUG_RETURN(0);
    4701                 :       }
    4702               0 :       if (flag == HA_ERR_END_OF_FILE)
    4703                 :       {
    4704               0 :         sort_param->max_pos= share->state.state.data_file_length;
    4705               0 :         DBUG_RETURN(-1);
    4706                 :       }
    4707                 :       /* Retry only if wrong record, not if disk error */
    4708               0 :       if (flag != HA_ERR_WRONG_IN_RECORD)
    4709                 :       {
    4710               0 :         retry_if_quick(sort_param, flag);
    4711               0 :         DBUG_RETURN(flag);
    4712                 :       }
    4713                 :     }
    4714                 :     break;                                      /* Impossible */
    4715                 :   }
    4716                 :   case STATIC_RECORD:
    4717                 :     for (;;)
    4718                 :     {
    4719               0 :       if (my_b_read(&sort_param->read_cache,sort_param->record,
    4720                 :                     share->base.pack_reclength))
    4721                 :       {
    4722               0 :         if (sort_param->read_cache.error)
    4723               0 :           param->out_flag |= O_DATA_LOST;
    4724               0 :         retry_if_quick(sort_param, my_errno);
    4725               0 :         DBUG_RETURN(-1);
    4726                 :       }
    4727               0 :       sort_param->start_recpos=sort_param->pos;
    4728               0 :       if (!sort_param->fix_datafile)
    4729                 :       {
    4730               0 :         sort_param->current_filepos= sort_param->pos;
    4731               0 :         if (sort_param->master)
    4732               0 :           share->state.split++;
    4733                 :       }
    4734               0 :       sort_param->max_pos=(sort_param->pos+=share->base.pack_reclength);
    4735               0 :       if (*sort_param->record)
    4736                 :       {
    4737               0 :         if (sort_param->calc_checksum)
    4738               0 :           param->glob_crc+= (info->cur_row.checksum=
    4739                 :                              _ma_static_checksum(info,sort_param->record));
    4740               0 :         DBUG_RETURN(0);
    4741                 :       }
    4742               0 :       if (!sort_param->fix_datafile && sort_param->master)
    4743                 :       {
    4744               0 :         share->state.state.del++;
    4745               0 :         share->state.state.empty+=share->base.pack_reclength;
    4746                 :       }
    4747                 :     }
    4748                 :   case DYNAMIC_RECORD:
    4749                 :   {
    4750                 :     uchar *to;
    4751               0 :     ha_checksum checksum= 0;
    4752               0 :     LINT_INIT(to);
    4753                 : 
    4754               0 :     pos=sort_param->pos;
    4755               0 :     searching=(sort_param->fix_datafile && (param->testflag & T_EXTEND));
    4756               0 :     parallel_flag= (sort_param->read_cache.file < 0) ? READING_NEXT : 0;
    4757                 :     for (;;)
    4758                 :     {
    4759               0 :       found_record=block_info.second_read= 0;
    4760               0 :       left_length=1;
    4761               0 :       if (searching)
    4762                 :       {
    4763               0 :         pos=MY_ALIGN(pos,MARIA_DYN_ALIGN_SIZE);
    4764               0 :         param->testflag|=T_RETRY_WITHOUT_QUICK;
    4765               0 :         sort_param->start_recpos=pos;
    4766                 :       }
    4767                 :       do
    4768                 :       {
    4769               0 :         if (pos > sort_param->max_pos)
    4770               0 :           sort_param->max_pos=pos;
    4771               0 :         if (pos & (MARIA_DYN_ALIGN_SIZE-1))
    4772                 :         {
    4773               0 :           if ((param->testflag & T_VERBOSE) || searching == 0)
    4774               0 :             _ma_check_print_info(param,"Wrong aligned block at %s",
    4775                 :                                 llstr(pos,llbuff));
    4776               0 :           if (searching)
    4777               0 :             goto try_next;
    4778                 :         }
    4779               0 :         if (found_record && pos == param->search_after_block)
    4780               0 :           _ma_check_print_info(param,"Block: %s used by record at %s",
    4781                 :                      llstr(param->search_after_block,llbuff),
    4782                 :                      llstr(sort_param->start_recpos,llbuff2));
    4783               0 :         if (_ma_read_cache(&sort_param->read_cache,
    4784                 :                            block_info.header, pos,
    4785                 :                            MARIA_BLOCK_INFO_HEADER_LENGTH,
    4786                 :                            (! found_record ? READING_NEXT : 0) |
    4787                 :                            parallel_flag | READING_HEADER))
    4788                 :         {
    4789               0 :           if (found_record)
    4790                 :           {
    4791               0 :             _ma_check_print_info(param,
    4792                 :                                 "Can't read whole record at %s (errno: %d)",
    4793                 :                                 llstr(sort_param->start_recpos,llbuff),errno);
    4794               0 :             goto try_next;
    4795                 :           }
    4796               0 :           DBUG_RETURN(-1);
    4797                 :         }
    4798               0 :         if (searching && ! sort_param->fix_datafile)
    4799                 :         {
    4800               0 :           param->error_printed=1;
    4801               0 :           param->retry_repair=1;
    4802               0 :           param->testflag|=T_RETRY_WITHOUT_QUICK;
    4803               0 :           DBUG_RETURN(1);       /* Something wrong with data */
    4804                 :         }
    4805               0 :         b_type= _ma_get_block_info(&block_info,-1,pos);
    4806               0 :         if ((b_type & (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
    4807                 :            ((b_type & BLOCK_FIRST) &&
    4808                 :              (block_info.rec_len < (uint) share->base.min_pack_length ||
    4809                 :               block_info.rec_len > (uint) share->base.max_pack_length)))
    4810                 :         {
    4811                 :           uint i;
    4812               0 :           if (param->testflag & T_VERBOSE || searching == 0)
    4813               0 :             _ma_check_print_info(param,
    4814                 :                                 "Wrong bytesec: %3d-%3d-%3d at %10s; Skipped",
    4815                 :                        block_info.header[0],block_info.header[1],
    4816                 :                        block_info.header[2],llstr(pos,llbuff));
    4817               0 :           if (found_record)
    4818               0 :             goto try_next;
    4819               0 :           block_info.second_read=0;
    4820               0 :           searching=1;
    4821                 :           /* Search after block in read header string */
    4822               0 :           for (i=MARIA_DYN_ALIGN_SIZE ;
    4823               0 :                i < MARIA_BLOCK_INFO_HEADER_LENGTH ;
    4824               0 :                i+= MARIA_DYN_ALIGN_SIZE)
    4825               0 :             if (block_info.header[i] >= 1 &&
    4826                 :                 block_info.header[i] <= MARIA_MAX_DYN_HEADER_BYTE)
    4827               0 :               break;
    4828               0 :           pos+=(ulong) i;
    4829               0 :           sort_param->start_recpos=pos;
    4830               0 :           continue;
    4831                 :         }
    4832               0 :         if (b_type & BLOCK_DELETED)
    4833                 :         {
    4834               0 :           my_bool error=0;
    4835               0 :           if (block_info.block_len+ (uint) (block_info.filepos-pos) <
    4836                 :               share->base.min_block_length)
    4837                 :           {
    4838               0 :             if (!searching)
    4839               0 :               _ma_check_print_info(param,
    4840                 :                                    "Deleted block with impossible length %lu "
    4841                 :                                    "at %s",
    4842                 :                                    block_info.block_len,llstr(pos,llbuff));
    4843               0 :             error=1;
    4844                 :           }
    4845                 :           else
    4846                 :           {
    4847               0 :             if ((block_info.next_filepos != HA_OFFSET_ERROR &&
    4848                 :                  block_info.next_filepos >=
    4849                 :                  share->state.state.data_file_length) ||
    4850                 :                 (block_info.prev_filepos != HA_OFFSET_ERROR &&
    4851                 :                  block_info.prev_filepos >=
    4852                 :                  share->state.state.data_file_length))
    4853                 :             {
    4854               0 :               if (!searching)
    4855               0 :                 _ma_check_print_info(param,
    4856                 :                                     "Delete link points outside datafile at "
    4857                 :                                      "%s",
    4858                 :                                      llstr(pos,llbuff));
    4859               0 :               error=1;
    4860                 :             }
    4861                 :           }
    4862               0 :           if (error)
    4863                 :           {
    4864               0 :             if (found_record)
    4865               0 :               goto try_next;
    4866               0 :             searching=1;
    4867               0 :             pos+= MARIA_DYN_ALIGN_SIZE;
    4868               0 :             sort_param->start_recpos=pos;
    4869               0 :             block_info.second_read=0;
    4870               0 :             continue;
    4871                 :           }
    4872                 :         }
    4873                 :         else
    4874                 :         {
    4875               0 :           if (block_info.block_len+ (uint) (block_info.filepos-pos) <
    4876                 :               share->base.min_block_length ||
    4877                 :               block_info.block_len > (uint) share->base.max_pack_length+
    4878                 :               MARIA_SPLIT_LENGTH)
    4879                 :           {
    4880               0 :             if (!searching)
    4881               0 :               _ma_check_print_info(param,
    4882                 :                                    "Found block with impossible length %lu "
    4883                 :                                    "at %s; Skipped",
    4884                 :                                    block_info.block_len+
    4885                 :                                    (uint) (block_info.filepos-pos),
    4886                 :                                    llstr(pos,llbuff));
    4887               0 :             if (found_record)
    4888               0 :               goto try_next;
    4889               0 :             searching=1;
    4890               0 :             pos+= MARIA_DYN_ALIGN_SIZE;
    4891               0 :             sort_param->start_recpos=pos;
    4892               0 :             block_info.second_read=0;
    4893               0 :             continue;
    4894                 :           }
    4895                 :         }
    4896               0 :         if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
    4897                 :         {
    4898               0 :           if (!sort_param->fix_datafile && sort_param->master &&
    4899                 :               (b_type & BLOCK_DELETED))
    4900                 :           {
    4901               0 :             share->state.state.empty+=block_info.block_len;
    4902               0 :             share->state.state.del++;
    4903               0 :             share->state.split++;
    4904                 :           }
    4905               0 :           if (found_record)
    4906               0 :             goto try_next;
    4907               0 :           if (searching)
    4908                 :           {
    4909               0 :             pos+=MARIA_DYN_ALIGN_SIZE;
    4910               0 :             sort_param->start_recpos=pos;
    4911                 :           }
    4912                 :           else
    4913               0 :             pos=block_info.filepos+block_info.block_len;
    4914               0 :           block_info.second_read=0;
    4915               0 :           continue;
    4916                 :         }
    4917                 : 
    4918               0 :         if (!sort_param->fix_datafile && sort_param->master)
    4919               0 :           share->state.split++;
    4920               0 :         if (! found_record++)
    4921                 :         {
    4922               0 :           sort_param->find_length=left_length=block_info.rec_len;
    4923               0 :           sort_param->start_recpos=pos;
    4924               0 :           if (!sort_param->fix_datafile)
    4925               0 :             sort_param->current_filepos= sort_param->start_recpos;
    4926               0 :           if (sort_param->fix_datafile && (param->testflag & T_EXTEND))
    4927               0 :             sort_param->pos=block_info.filepos+1;
    4928                 :           else
    4929               0 :             sort_param->pos=block_info.filepos+block_info.block_len;
    4930               0 :           if (share->base.blobs)
    4931                 :           {
    4932               0 :             if (_ma_alloc_buffer(&sort_param->rec_buff,
    4933                 :                                  &sort_param->rec_buff_size,
    4934                 :                                  block_info.rec_len +
    4935                 :                                  share->base.extra_rec_buff_size))
    4936                 : 
    4937                 :             {
    4938               0 :               if (param->max_record_length >= block_info.rec_len)
    4939                 :               {
    4940               0 :                 _ma_check_print_error(param,"Not enough memory for blob at %s "
    4941                 :                                       "(need %lu)",
    4942                 :                                      llstr(sort_param->start_recpos,llbuff),
    4943                 :                                      (ulong) block_info.rec_len);
    4944               0 :                 DBUG_RETURN(1);
    4945                 :               }
    4946                 :               else
    4947                 :               {
    4948               0 :                 _ma_check_print_info(param,"Not enough memory for blob at %s "
    4949                 :                                      "(need %lu); Row skipped",
    4950                 :                                     llstr(sort_param->start_recpos,llbuff),
    4951                 :                                     (ulong) block_info.rec_len);
    4952               0 :                 goto try_next;
    4953                 :               }
    4954                 :             }
    4955                 :           }
    4956               0 :           to= sort_param->rec_buff;
    4957                 :         }
    4958               0 :         if (left_length < block_info.data_len || ! block_info.data_len)
    4959                 :         {
    4960               0 :           _ma_check_print_info(param,
    4961                 :                               "Found block with too small length at %s; "
    4962                 :                                "Skipped",
    4963                 :                                llstr(sort_param->start_recpos,llbuff));
    4964               0 :           goto try_next;
    4965                 :         }
    4966               0 :         if (block_info.filepos + block_info.data_len >
    4967                 :             sort_param->read_cache.end_of_file)
    4968                 :         {
    4969               0 :           _ma_check_print_info(param,
    4970                 :                               "Found block that points outside data file "
    4971                 :                                "at %s",
    4972                 :                                llstr(sort_param->start_recpos,llbuff));
    4973               0 :           goto try_next;
    4974                 :         }
    4975                 :         /*
    4976                 :           Copy information that is already read. Avoid accessing data
    4977                 :           below the cache start. This could happen if the header
    4978                 :           streched over the end of the previous buffer contents.
    4979                 :         */
    4980                 :         {
    4981               0 :           uint header_len= (uint) (block_info.filepos - pos);
    4982               0 :           uint prefetch_len= (MARIA_BLOCK_INFO_HEADER_LENGTH - header_len);
    4983                 : 
    4984               0 :           if (prefetch_len > block_info.data_len)
    4985               0 :             prefetch_len= block_info.data_len;
    4986               0 :           if (prefetch_len)
    4987                 :           {
    4988               0 :             memcpy(to, block_info.header + header_len, prefetch_len);
    4989               0 :             block_info.filepos+= prefetch_len;
    4990               0 :             block_info.data_len-= prefetch_len;
    4991               0 :             left_length-= prefetch_len;
    4992               0 :             to+= prefetch_len;
    4993                 :           }
    4994                 :         }
    4995               0 :         if (block_info.data_len &&
    4996                 :             _ma_read_cache(&sort_param->read_cache,to,block_info.filepos,
    4997                 :                            block_info.data_len,
    4998                 :                            (found_record == 1 ? READING_NEXT : 0) |
    4999                 :                            parallel_flag))
    5000                 :         {
    5001               0 :           _ma_check_print_info(param,
    5002                 :                               "Read error for block at: %s (error: %d); "
    5003                 :                                "Skipped",
    5004                 :                               llstr(block_info.filepos,llbuff),my_errno);
    5005               0 :           goto try_next;
    5006                 :         }
    5007               0 :         left_length-=block_info.data_len;
    5008               0 :         to+=block_info.data_len;
    5009               0 :         pos=block_info.next_filepos;
    5010               0 :         if (pos == HA_OFFSET_ERROR && left_length)
    5011                 :         {
    5012               0 :           _ma_check_print_info(param,
    5013                 :                                "Wrong block with wrong total length "
    5014                 :                                "starting at %s",
    5015                 :                               llstr(sort_param->start_recpos,llbuff));
    5016               0 :           goto try_next;
    5017                 :         }
    5018               0 :         if (pos + MARIA_BLOCK_INFO_HEADER_LENGTH >
    5019                 :             sort_param->read_cache.end_of_file)
    5020                 :         {
    5021               0 :           _ma_check_print_info(param,
    5022                 :                                "Found link that points at %s (outside data "
    5023                 :                                "file) at %s",
    5024                 :                               llstr(pos,llbuff2),
    5025                 :                               llstr(sort_param->start_recpos,llbuff));
    5026               0 :           goto try_next;
    5027                 :         }
    5028               0 :       } while (left_length);
    5029                 : 
    5030               0 :       if (_ma_rec_unpack(info,sort_param->record,sort_param->rec_buff,
    5031                 :                          sort_param->find_length) != MY_FILE_ERROR)
    5032                 :       {
    5033               0 :         if (sort_param->read_cache.error < 0)
    5034               0 :           DBUG_RETURN(1);
    5035               0 :         if (sort_param->calc_checksum)
    5036               0 :           checksum= (share->calc_check_checksum)(info, sort_param->record);
    5037               0 :         if ((param->testflag & (T_EXTEND | T_REP)) || searching)
    5038                 :         {
    5039               0 :           if (_ma_rec_check(info, sort_param->record, sort_param->rec_buff,
    5040                 :                             sort_param->find_length,
    5041                 :                             (param->testflag & T_QUICK) &&
    5042                 :                             sort_param->calc_checksum &&
    5043                 :                             test(share->calc_checksum), checksum))
    5044                 :           {
    5045               0 :             _ma_check_print_info(param,"Found wrong packed record at %s",
    5046                 :                                 llstr(sort_param->start_recpos,llbuff));
    5047               0 :             goto try_next;
    5048                 :           }
    5049                 :         }
    5050               0 :         if (sort_param->calc_checksum)
    5051               0 :           param->glob_crc+= checksum;
    5052               0 :         DBUG_RETURN(0);
    5053                 :       }
    5054               0 :       if (!searching)
    5055               0 :         _ma_check_print_info(param,"Key %d - Found wrong stored record at %s",
    5056                 :                             sort_param->key+1,
    5057                 :                             llstr(sort_param->start_recpos,llbuff));
    5058               0 :     try_next:
    5059               0 :       pos=(sort_param->start_recpos+=MARIA_DYN_ALIGN_SIZE);
    5060               0 :       searching=1;
    5061               0 :     }
    5062                 :   }
    5063                 :   case COMPRESSED_RECORD:
    5064               0 :     for (searching=0 ;; searching=1, sort_param->pos++)
    5065                 :     {
    5066               0 :       if (_ma_read_cache(&sort_param->read_cache, block_info.header,
    5067                 :                          sort_param->pos,
    5068                 :                          share->pack.ref_length,READING_NEXT))
    5069               0 :         DBUG_RETURN(-1);
    5070               0 :       if (searching && ! sort_param->fix_datafile)
    5071                 :       {
    5072               0 :         param->error_printed=1;
    5073               0 :         param->retry_repair=1;
    5074               0 :         param->testflag|=T_RETRY_WITHOUT_QUICK;
    5075               0 :         DBUG_RETURN(1);         /* Something wrong with data */
    5076                 :       }
    5077               0 :       sort_param->start_recpos=sort_param->pos;
    5078               0 :       if (_ma_pack_get_block_info(info, &sort_param->bit_buff, &block_info,
    5079                 :                                   &sort_param->rec_buff,
    5080                 :                                   &sort_param->rec_buff_size, -1,
    5081                 :                                   sort_param->pos))
    5082               0 :         DBUG_RETURN(-1);
    5083               0 :       if (!block_info.rec_len &&
    5084                 :           sort_param->pos + MEMMAP_EXTRA_MARGIN ==
    5085                 :           sort_param->read_cache.end_of_file)
    5086               0 :         DBUG_RETURN(-1);
    5087               0 :       if (block_info.rec_len < (uint) share->min_pack_length ||
    5088                 :           block_info.rec_len > (uint) share->max_pack_length)
    5089                 :       {
    5090               0 :         if (! searching)
    5091               0 :           _ma_check_print_info(param,
    5092                 :                                "Found block with wrong recordlength: %lu "
    5093                 :                                "at %s\n",
    5094                 :                                block_info.rec_len,
    5095                 :                                llstr(sort_param->pos,llbuff));
    5096                 :         continue;
    5097                 :       }
    5098               0 :       if (_ma_read_cache(&sort_param->read_cache, sort_param->rec_buff,
    5099                 :                          block_info.filepos, block_info.rec_len,
    5100                 :                          READING_NEXT))
    5101                 :       {
    5102               0 :         if (! searching)
    5103               0 :           _ma_check_print_info(param,"Couldn't read whole record from %s",
    5104                 :                               llstr(sort_param->pos,llbuff));
    5105                 :         continue;
    5106                 :       }
    5107                 : #ifdef HAVE_purify
    5108                 :       bzero(sort_param->rec_buff + block_info.rec_len,
    5109                 :             share->base.extra_rec_buff_size);
    5110                 : #endif
    5111               0 :       if (_ma_pack_rec_unpack(info, &sort_param->bit_buff, sort_param->record,
    5112                 :                               sort_param->rec_buff, block_info.rec_len))
    5113                 :       {
    5114               0 :         if (! searching)
    5115               0 :           _ma_check_print_info(param,"Found wrong record at %s",
    5116                 :                               llstr(sort_param->pos,llbuff));
    5117                 :         continue;
    5118                 :       }
    5119               0 :       if (!sort_param->fix_datafile)
    5120                 :       {
    5121               0 :         sort_param->current_filepos= sort_param->pos;
    5122               0 :         if (sort_param->master)
    5123               0 :           share->state.split++;
    5124                 :       }
    5125               0 :       sort_param->max_pos= (sort_param->pos=block_info.filepos+
    5126                 :                             block_info.rec_len);
    5127               0 :       info->packed_length=block_info.rec_len;
    5128                 : 
    5129               0 :       if (sort_param->calc_checksum)
    5130                 :       {
    5131               0 :         info->cur_row.checksum= (*share->calc_check_checksum)(info,
    5132                 :                                                                 sort_param->
    5133                 :                                                                 record);
    5134               0 :         param->glob_crc+= info->cur_row.checksum;
    5135                 :       }
    5136               0 :       DBUG_RETURN(0);
    5137               0 :     }
    5138                 :   }
    5139               0 :   DBUG_RETURN(1);               /* Impossible */
    5140                 : }
    5141                 : 
    5142                 : 
    5143                 : /**
    5144                 :    @brief Write record to new file.
    5145                 : 
    5146                 :    @fn    _ma_sort_write_record()
    5147                 :    @param sort_param                Sort parameters.
    5148                 : 
    5149                 :    @note
    5150                 :    This is only called by a master thread if parallel repair is used.
    5151                 : 
    5152                 :    @return
    5153                 :    @retval  0   OK
    5154                 :                 sort_param->current_filepos points to inserted record for
    5155                 :                 block_records and to the place for the next record for
    5156                 :                 other row types.
    5157                 :                 sort_param->filepos points to end of file
    5158                 :   @retval   1   Error
    5159                 : */
    5160                 : 
    5161                 : int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
    5162               0 : {
    5163                 :   int flag;
    5164                 :   uint length;
    5165                 :   ulong block_length,reclength;
    5166                 :   uchar *from;
    5167                 :   uchar block_buff[8];
    5168               0 :   MARIA_SORT_INFO *sort_info=sort_param->sort_info;
    5169               0 :   HA_CHECK *param= sort_info->param;
    5170               0 :   MARIA_HA *info= sort_info->new_info;
    5171               0 :   MARIA_SHARE *share= info->s;
    5172               0 :   DBUG_ENTER("_ma_sort_write_record");
    5173                 : 
    5174               0 :   if (sort_param->fix_datafile)
    5175                 :   {
    5176               0 :     sort_param->current_filepos= sort_param->filepos;
    5177               0 :     switch (sort_info->new_data_file_type) {
    5178                 :     case BLOCK_RECORD:
    5179               0 :       if ((sort_param->current_filepos=
    5180                 :            (*share->write_record_init)(info, sort_param->record)) ==
    5181                 :           HA_OFFSET_ERROR)
    5182               0 :         DBUG_RETURN(1);
    5183                 :       /* Pointer to end of file */
    5184               0 :       sort_param->filepos= share->state.state.data_file_length;
    5185               0 :       break;
    5186                 :     case STATIC_RECORD:
    5187               0 :       if (my_b_write(&info->rec_cache,sort_param->record,
    5188                 :                      share->base.pack_reclength))
    5189                 :       {
    5190               0 :         _ma_check_print_error(param,"%d when writing to datafile",my_errno);
    5191               0 :         DBUG_RETURN(1);
    5192                 :       }
    5193               0 :       sort_param->filepos+=share->base.pack_reclength;
    5194               0 :       share->state.split++;
    5195               0 :       break;
    5196                 :     case DYNAMIC_RECORD:
    5197               0 :       if (! info->blobs)
    5198               0 :         from=sort_param->rec_buff;
    5199                 :       else
    5200                 :       {
    5201                 :         /* must be sure that local buffer is big enough */
    5202               0 :         reclength=share->base.pack_reclength+
    5203                 :           _ma_calc_total_blob_length(info,sort_param->record)+
    5204                 :           ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
    5205                 :           MARIA_DYN_DELETE_BLOCK_HEADER;
    5206               0 :         if (sort_info->buff_length < reclength)
    5207                 :         {
    5208               0 :           if (!(sort_info->buff=my_realloc(sort_info->buff, (uint) reclength,
    5209                 :                                            MYF(MY_FREE_ON_ERROR |
    5210                 :                                                MY_ALLOW_ZERO_PTR))))
    5211               0 :             DBUG_RETURN(1);
    5212               0 :           sort_info->buff_length=reclength;
    5213                 :         }
    5214               0 :         from= (uchar *) sort_info->buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER);
    5215                 :       }
    5216                 :       /* We can use info->checksum here as only one thread calls this */
    5217               0 :       info->cur_row.checksum= (*share->calc_check_checksum)(info,
    5218                 :                                                               sort_param->
    5219                 :                                                               record);
    5220               0 :       reclength= _ma_rec_pack(info,from,sort_param->record);
    5221               0 :       flag=0;
    5222                 : 
    5223                 :       do
    5224                 :       {
    5225               0 :         block_length=reclength+ 3 + test(reclength >= (65520-3));
    5226               0 :         if (block_length < share->base.min_block_length)
    5227               0 :           block_length=share->base.min_block_length;
    5228               0 :         info->update|=HA_STATE_WRITE_AT_END;
    5229               0 :         block_length=MY_ALIGN(block_length,MARIA_DYN_ALIGN_SIZE);
    5230               0 :         if (block_length > MARIA_MAX_BLOCK_LENGTH)
    5231               0 :           block_length=MARIA_MAX_BLOCK_LENGTH;
    5232               0 :         if (_ma_write_part_record(info,0L,block_length,
    5233                 :                                   sort_param->filepos+block_length,
    5234                 :                                   &from,&reclength,&flag))
    5235                 :         {
    5236               0 :           _ma_check_print_error(param,"%d when writing to datafile",my_errno);
    5237               0 :           DBUG_RETURN(1);
    5238                 :         }
    5239               0 :         sort_param->filepos+=block_length;
    5240               0 :         share->state.split++;
    5241               0 :       } while (reclength);
    5242                 :       break;
    5243                 :     case COMPRESSED_RECORD:
    5244               0 :       reclength=info->packed_length;
    5245               0 :       length= _ma_save_pack_length((uint) share->pack.version, block_buff,
    5246                 :                                reclength);
    5247               0 :       if (share->base.blobs)
    5248               0 :         length+= _ma_save_pack_length((uint) share->pack.version,
    5249                 :                                   block_buff + length, info->blob_length);
    5250               0 :       if (my_b_write(&info->rec_cache,block_buff,length) ||
    5251                 :           my_b_write(&info->rec_cache, sort_param->rec_buff, reclength))
    5252                 :       {
    5253               0 :         _ma_check_print_error(param,"%d when writing to datafile",my_errno);
    5254               0 :         DBUG_RETURN(1);
    5255                 :       }
    5256               0 :       sort_param->filepos+=reclength+length;
    5257               0 :       share->state.split++;
    5258                 :       break;
    5259                 :     }
    5260                 :   }
    5261               0 :   if (sort_param->master)
    5262                 :   {
    5263               0 :     share->state.state.records++;
    5264               0 :     if ((param->testflag & T_WRITE_LOOP) &&
    5265                 :         (share->state.state.records % WRITE_COUNT) == 0)
    5266                 :     {
    5267                 :       char llbuff[22];
    5268               0 :       printf("%s\r", llstr(share->state.state.records,llbuff));
    5269               0 :       VOID(fflush(stdout));
    5270                 :     }
    5271                 :   }
    5272               0 :   DBUG_RETURN(0);
    5273                 : } /* _ma_sort_write_record */
    5274                 : 
    5275                 : 
    5276                 : /* Compare two keys from _ma_create_index_by_sort */
    5277                 : 
    5278                 : static int sort_key_cmp(MARIA_SORT_PARAM *sort_param, const void *a,
    5279                 :                         const void *b)
    5280               0 : {
    5281                 :   uint not_used[2];
    5282               0 :   return (ha_key_cmp(sort_param->seg, *((uchar* const *) a),
    5283                 :                      *((uchar* const *) b),
    5284                 :                      USE_WHOLE_KEY, SEARCH_SAME, not_used));
    5285                 : } /* sort_key_cmp */
    5286                 : 
    5287                 : 
    5288                 : static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a)
    5289               0 : {
    5290                 :   uint diff_pos[2];
    5291                 :   char llbuff[22],llbuff2[22];
    5292               0 :   MARIA_SORT_INFO *sort_info=sort_param->sort_info;
    5293               0 :   HA_CHECK *param= sort_info->param;
    5294                 :   int cmp;
    5295                 : 
    5296               0 :   if (sort_info->key_block->inited)
    5297                 :   {
    5298               0 :     cmp= ha_key_cmp(sort_param->seg, sort_info->key_block->lastkey,
    5299                 :                     a, USE_WHOLE_KEY,
    5300                 :                     SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT,
    5301                 :                     diff_pos);
    5302               0 :     if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
    5303               0 :       ha_key_cmp(sort_param->seg, sort_info->key_block->lastkey,
    5304                 :                  a, USE_WHOLE_KEY,
    5305                 :                  SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
    5306               0 :     else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
    5307                 :     {
    5308               0 :       diff_pos[0]= maria_collect_stats_nonulls_next(sort_param->seg,
    5309                 :                                                  sort_param->notnull,
    5310                 :                                                  sort_info->key_block->lastkey,
    5311                 :                                                  a);
    5312                 :     }
    5313               0 :     sort_param->unique[diff_pos[0]-1]++;
    5314                 :   }
    5315                 :   else
    5316                 :   {
    5317               0 :     cmp= -1;
    5318               0 :     if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
    5319               0 :       maria_collect_stats_nonulls_first(sort_param->seg, sort_param->notnull,
    5320                 :                                         a);
    5321                 :   }
    5322               0 :   if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0)
    5323                 :   {
    5324               0 :     sort_info->dupp++;
    5325               0 :     sort_info->info->cur_row.lastpos= get_record_for_key(sort_param->keyinfo,
    5326                 :                                                          a);
    5327               0 :     _ma_check_print_warning(param,
    5328                 :                            "Duplicate key %2u for record at %10s against "
    5329                 :                             "record at %10s",
    5330                 :                             sort_param->key + 1,
    5331                 :                             llstr(sort_info->info->cur_row.lastpos, llbuff),
    5332                 :                             llstr(get_record_for_key(sort_param->keyinfo,
    5333                 :                                                      sort_info->key_block->
    5334                 :                                                      lastkey),
    5335                 :                                   llbuff2));
    5336               0 :     param->testflag|=T_RETRY_WITHOUT_QUICK;
    5337               0 :     if (sort_info->param->testflag & T_VERBOSE)
    5338               0 :       _ma_print_keydata(stdout,sort_param->seg, a, USE_WHOLE_KEY);
    5339               0 :     return (sort_delete_record(sort_param));
    5340                 :   }
    5341                 : #ifndef DBUG_OFF
    5342               0 :   if (cmp > 0)
    5343                 :   {
    5344               0 :     _ma_check_print_error(param,
    5345                 :                          "Internal error: Keys are not in order from sort");
    5346               0 :     return(1);
    5347                 :   }
    5348                 : #endif
    5349               0 :   return (sort_insert_key(sort_param, sort_info->key_block,
    5350                 :                           a, HA_OFFSET_ERROR));
    5351                 : } /* sort_key_write */
    5352                 : 
    5353                 : 
    5354                 : int _ma_sort_ft_buf_flush(MARIA_SORT_PARAM *sort_param)
    5355               0 : {
    5356               0 :   MARIA_SORT_INFO *sort_info=sort_param->sort_info;
    5357               0 :   SORT_KEY_BLOCKS *key_block=sort_info->key_block;
    5358               0 :   MARIA_SHARE *share=sort_info->info->s;
    5359                 :   uint val_off, val_len;
    5360                 :   int error;
    5361               0 :   SORT_FT_BUF *maria_ft_buf=sort_info->ft_buf;
    5362                 :   uchar *from, *to;
    5363                 : 
    5364               0 :   val_len=share->ft2_keyinfo.keylength;
    5365               0 :   get_key_full_length_rdonly(val_off, maria_ft_buf->lastkey);
    5366               0 :   to= maria_ft_buf->lastkey+val_off;
    5367                 : 
    5368               0 :   if (maria_ft_buf->buf)
    5369                 :   {
    5370                 :     /* flushing first-level tree */
    5371               0 :     error= sort_insert_key(sort_param,key_block,maria_ft_buf->lastkey,
    5372                 :                            HA_OFFSET_ERROR);
    5373               0 :     for (from=to+val_len;
    5374               0 :          !error && from < maria_ft_buf->buf;
    5375               0 :          from+= val_len)
    5376                 :     {
    5377               0 :       memcpy(to, from, val_len);
    5378               0 :       error= sort_insert_key(sort_param,key_block,maria_ft_buf->lastkey,
    5379                 :                              HA_OFFSET_ERROR);
    5380                 :     }
    5381               0 :     return error;
    5382                 :   }
    5383                 :   /* flushing second-level tree keyblocks */
    5384               0 :   error=_ma_flush_pending_blocks(sort_param);
    5385                 :   /* updating lastkey with second-level tree info */
    5386               0 :   ft_intXstore(maria_ft_buf->lastkey+val_off, -maria_ft_buf->count);
    5387               0 :   _ma_dpointer(sort_info->info->s, maria_ft_buf->lastkey+val_off+HA_FT_WLEN,
    5388                 :       share->state.key_root[sort_param->key]);
    5389                 :   /* restoring first level tree data in sort_info/sort_param */
    5390               0 :   sort_info->key_block=sort_info->key_block_end- sort_info->param->sort_key_blocks;
    5391               0 :   sort_param->keyinfo=share->keyinfo+sort_param->key;
    5392               0 :   share->state.key_root[sort_param->key]=HA_OFFSET_ERROR;
    5393                 :   /* writing lastkey in first-level tree */
    5394               0 :   return error ? error :
    5395                 :                  sort_insert_key(sort_param,sort_info->key_block,
    5396                 :                                  maria_ft_buf->lastkey,HA_OFFSET_ERROR);
    5397                 : }
    5398                 : 
    5399                 : 
    5400                 : static int sort_maria_ft_key_write(MARIA_SORT_PARAM *sort_param,
    5401                 :                                    const uchar *a)
    5402               0 : {
    5403                 :   uint a_len, val_off, val_len, error;
    5404               0 :   MARIA_SORT_INFO *sort_info= sort_param->sort_info;
    5405               0 :   SORT_FT_BUF *ft_buf= sort_info->ft_buf;
    5406               0 :   SORT_KEY_BLOCKS *key_block= sort_info->key_block;
    5407               0 :   MARIA_SHARE *share= sort_info->info->s;
    5408                 : 
    5409               0 :   val_len=HA_FT_WLEN+share->base.rec_reflength;
    5410               0 :   get_key_full_length_rdonly(a_len, a);
    5411                 : 
    5412               0 :   if (!ft_buf)
    5413                 :   {
    5414                 :     /*
    5415                 :       use two-level tree only if key_reflength fits in rec_reflength place
    5416                 :       and row format is NOT static - for _ma_dpointer not to garble offsets
    5417                 :      */
    5418               0 :     if ((share->base.key_reflength <=
    5419                 :          share->base.rec_reflength) &&
    5420                 :         (share->options &
    5421                 :           (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
    5422               0 :       ft_buf= (SORT_FT_BUF *)my_malloc(sort_param->keyinfo->block_length +
    5423                 :                                        sizeof(SORT_FT_BUF), MYF(MY_WME));
    5424                 : 
    5425               0 :     if (!ft_buf)
    5426                 :     {
    5427               0 :       sort_param->key_write=sort_key_write;
    5428               0 :       return sort_key_write(sort_param, a);
    5429                 :     }
    5430               0 :     sort_info->ft_buf= ft_buf;
    5431               0 :     goto word_init_ft_buf;              /* no need to duplicate the code */
    5432                 :   }
    5433               0 :   get_key_full_length_rdonly(val_off, ft_buf->lastkey);
    5434                 : 
    5435               0 :   if (ha_compare_text(sort_param->seg->charset,
    5436                 :                       a+1,a_len-1,
    5437                 :                       ft_buf->lastkey+1,val_off-1, 0, 0)==0)
    5438                 :   {
    5439                 :     uchar *p;
    5440               0 :     if (!ft_buf->buf)                   /* store in second-level tree */
    5441                 :     {
    5442               0 :       ft_buf->count++;
    5443               0 :       return sort_insert_key(sort_param,key_block,
    5444                 :                              a + a_len, HA_OFFSET_ERROR);
    5445                 :     }
    5446                 : 
    5447                 :     /* storing the key in the buffer. */
    5448               0 :     memcpy (ft_buf->buf, (const char *)a+a_len, val_len);
    5449               0 :     ft_buf->buf+=val_len;
    5450               0 :     if (ft_buf->buf < ft_buf->end)
    5451               0 :       return 0;
    5452                 : 
    5453                 :     /* converting to two-level tree */
    5454               0 :     p=ft_buf->lastkey+val_off;
    5455                 : 
    5456               0 :     while (key_block->inited)
    5457               0 :       key_block++;
    5458               0 :     sort_info->key_block=key_block;
    5459               0 :     sort_param->keyinfo= &share->ft2_keyinfo;
    5460               0 :     ft_buf->count=(ft_buf->buf - p)/val_len;
    5461                 : 
    5462                 :     /* flushing buffer to second-level tree */
    5463               0 :     for (error=0; !error && p < ft_buf->buf; p+= val_len)
    5464               0 :       error=sort_insert_key(sort_param,key_block,p,HA_OFFSET_ERROR);
    5465               0 :     ft_buf->buf=0;
    5466               0 :     return error;
    5467                 :   }
    5468                 : 
    5469                 :   /* flushing buffer */
    5470               0 :   if ((error=_ma_sort_ft_buf_flush(sort_param)))
    5471               0 :     return error;
    5472                 : 
    5473               0 : word_init_ft_buf:
    5474               0 :   a_len+=val_len;
    5475               0 :   memcpy(ft_buf->lastkey, a, a_len);
    5476               0 :   ft_buf->buf=ft_buf->lastkey+a_len;
    5477                 :   /*
    5478                 :     32 is just a safety margin here
    5479                 :     (at least max(val_len, sizeof(nod_flag)) should be there).
    5480                 :     May be better performance could be achieved if we'd put
    5481                 :       (sort_info->keyinfo->block_length-32)/XXX
    5482                 :       instead.
    5483                 :         TODO: benchmark the best value for XXX.
    5484                 :   */
    5485               0 :   ft_buf->end= ft_buf->lastkey+ (sort_param->keyinfo->block_length-32);
    5486               0 :   return 0;
    5487                 : } /* sort_maria_ft_key_write */
    5488                 : 
    5489                 : 
    5490                 : /* get pointer to record from a key */
    5491                 : 
    5492                 : static my_off_t get_record_for_key(MARIA_KEYDEF *keyinfo,
    5493                 :                                    const uchar *key_data)
    5494               0 : {
    5495                 :   MARIA_KEY key;
    5496               0 :   key.keyinfo= keyinfo;
    5497               0 :   key.data= (uchar*) key_data;
    5498               0 :   key.data_length= _ma_keylength(keyinfo, key_data);
    5499               0 :   return _ma_row_pos_from_key(&key);
    5500                 : } /* get_record_for_key */
    5501                 : 
    5502                 : 
    5503                 : /* Insert a key in sort-key-blocks */
    5504                 : 
    5505                 : static int sort_insert_key(MARIA_SORT_PARAM *sort_param,
    5506                 :                            register SORT_KEY_BLOCKS *key_block,
    5507                 :                            const uchar *key,
    5508                 :                            my_off_t prev_block)
    5509               0 : {
    5510                 :   uint a_length,t_length,nod_flag;
    5511                 :   my_off_t filepos,key_file_length;
    5512                 :   uchar *anc_buff,*lastkey;
    5513                 :   MARIA_KEY_PARAM s_temp;
    5514               0 :   MARIA_KEYDEF *keyinfo=sort_param->keyinfo;
    5515               0 :   MARIA_SORT_INFO *sort_info= sort_param->sort_info;
    5516               0 :   HA_CHECK *param=sort_info->param;
    5517               0 :   MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
    5518                 :   MARIA_KEY tmp_key;
    5519               0 :   MARIA_HA *info= sort_info->info;
    5520               0 :   MARIA_SHARE *share= info->s;
    5521               0 :   DBUG_ENTER("sort_insert_key");
    5522                 : 
    5523               0 :   anc_buff= key_block->buff;
    5524               0 :   lastkey=key_block->lastkey;
    5525               0 :   nod_flag= (key_block == sort_info->key_block ? 0 :
    5526                 :              share->base.key_reflength);
    5527                 : 
    5528               0 :   if (!key_block->inited)
    5529                 :   {
    5530               0 :     key_block->inited=1;
    5531               0 :     if (key_block == sort_info->key_block_end)
    5532                 :     {
    5533               0 :       _ma_check_print_error(param,
    5534                 :                             "To many key-block-levels; "
    5535                 :                             "Try increasing sort_key_blocks");
    5536               0 :       DBUG_RETURN(1);
    5537                 :     }
    5538               0 :     a_length= share->keypage_header + nod_flag;
    5539               0 :     key_block->end_pos= anc_buff + share->keypage_header;
    5540               0 :     bzero(anc_buff, share->keypage_header);
    5541               0 :     _ma_store_keynr(share, anc_buff, (uint) (sort_param->keyinfo -
    5542                 :                                             share->keyinfo));
    5543               0 :     lastkey=0;                                  /* No previous key in block */
    5544                 :   }
    5545                 :   else
    5546               0 :     a_length= _ma_get_page_used(share, anc_buff);
    5547                 : 
    5548                 :         /* Save pointer to previous block */
    5549               0 :   if (nod_flag)
    5550                 :   {
    5551               0 :     _ma_store_keypage_flag(share, anc_buff, KEYPAGE_FLAG_ISNOD);
    5552               0 :     _ma_kpointer(info,key_block->end_pos,prev_block);
    5553                 :   }
    5554                 : 
    5555               0 :   tmp_key.keyinfo= keyinfo;
    5556               0 :   tmp_key.data= (uchar*) key;
    5557               0 :   tmp_key.data_length= _ma_keylength(keyinfo, key) - share->base.rec_reflength;
    5558               0 :   tmp_key.ref_length=  share->base.rec_reflength;
    5559                 : 
    5560               0 :   t_length= (*keyinfo->pack_key)(&tmp_key, nod_flag,
    5561                 :                                  (uchar*) 0, lastkey, lastkey, &s_temp);
    5562               0 :   (*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp);
    5563               0 :   a_length+=t_length;
    5564               0 :   _ma_store_page_used(share, anc_buff, a_length);
    5565               0 :   key_block->end_pos+=t_length;
    5566               0 :   if (a_length <= (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
    5567                 :   {
    5568                 :     MARIA_KEY tmp_key2;
    5569               0 :     tmp_key2.data= key_block->lastkey;
    5570               0 :     _ma_copy_key(&tmp_key2, &tmp_key);
    5571               0 :     key_block->last_length=a_length-t_length;
    5572               0 :     DBUG_RETURN(0);
    5573                 :   }
    5574                 : 
    5575                 :   /* Fill block with end-zero and write filled block */
    5576               0 :   _ma_store_page_used(share, anc_buff, key_block->last_length);
    5577               0 :   bzero(anc_buff+key_block->last_length,
    5578                 :         keyinfo->block_length- key_block->last_length);
    5579               0 :   key_file_length=share->state.state.key_file_length;
    5580               0 :   if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) == HA_OFFSET_ERROR)
    5581               0 :     DBUG_RETURN(1);
    5582               0 :   _ma_fast_unlock_key_del(info);
    5583                 : 
    5584                 :   /* If we read the page from the key cache, we have to write it back to it */
    5585               0 :   if (page_link->changed)
    5586                 :   {
    5587                 :     MARIA_PAGE page;
    5588               0 :     pop_dynamic(&info->pinned_pages);
    5589               0 :     _ma_page_setup(&page, info, keyinfo, filepos, anc_buff);
    5590               0 :     if (_ma_write_keypage(&page, PAGECACHE_LOCK_WRITE_UNLOCK, DFLT_INIT_HITS))
    5591               0 :       DBUG_RETURN(1);
    5592                 :   }
    5593                 :   else
    5594                 :   {
    5595               0 :     put_crc(anc_buff, filepos, share);
    5596               0 :     if (my_pwrite(share->kfile.file, anc_buff,
    5597                 :                   (uint) keyinfo->block_length, filepos, param->myf_rw))
    5598               0 :       DBUG_RETURN(1);
    5599                 :   }
    5600               0 :   DBUG_DUMP("buff", anc_buff, _ma_get_page_used(share, anc_buff));
    5601                 : 
    5602                 :         /* Write separator-key to block in next level */
    5603               0 :   if (sort_insert_key(sort_param,key_block+1,key_block->lastkey,filepos))
    5604               0 :     DBUG_RETURN(1);
    5605                 : 
    5606                 :         /* clear old block and write new key in it */
    5607               0 :   key_block->inited=0;
    5608               0 :   DBUG_RETURN(sort_insert_key(sort_param, key_block,key,prev_block));
    5609                 : } /* sort_insert_key */
    5610                 : 
    5611                 : 
    5612                 : /* Delete record when we found a duplicated key */
    5613                 : 
    5614                 : static int sort_delete_record(MARIA_SORT_PARAM *sort_param)
    5615               0 : {
    5616                 :   uint i;
    5617                 :   int old_file,error;
    5618                 :   uchar *key;
    5619               0 :   MARIA_SORT_INFO *sort_info=sort_param->sort_info;
    5620               0 :   HA_CHECK *param=sort_info->param;
    5621               0 :   MARIA_HA *row_info= sort_info->new_info, *key_info= sort_info->info;
    5622               0 :   DBUG_ENTER("sort_delete_record");
    5623                 : 
    5624               0 :   if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
    5625                 :   {
    5626               0 :     _ma_check_print_error(param,
    5627                 :                          "Quick-recover aborted; Run recovery without switch "
    5628                 :                           "-q or with switch -qq");
    5629               0 :     DBUG_RETURN(1);
    5630                 :   }
    5631               0 :   if (key_info->s->options & HA_OPTION_COMPRESS_RECORD)
    5632                 :   {
    5633               0 :     _ma_check_print_error(param,
    5634                 :                           "Recover aborted; Can't run standard recovery on "
    5635                 :                           "compressed tables with errors in data-file. "
    5636                 :                           "Use 'maria_chk --safe-recover' to fix it");
    5637               0 :     DBUG_RETURN(1);
    5638                 :   }
    5639                 : 
    5640               0 :   old_file= row_info->dfile.file;
    5641                 :   /* This only affects static and dynamic row formats */
    5642               0 :   row_info->dfile.file= row_info->rec_cache.file;
    5643               0 :   if (flush_io_cache(&row_info->rec_cache))
    5644               0 :     DBUG_RETURN(1);
    5645                 : 
    5646               0 :   key= key_info->lastkey_buff + key_info->s->base.max_key_length;
    5647               0 :   if ((error=(*row_info->s->read_record)(row_info, sort_param->record,
    5648                 :                                          key_info->cur_row.lastpos)) &&
    5649                 :         error != HA_ERR_RECORD_DELETED)
    5650                 :   {
    5651               0 :     _ma_check_print_error(param,"Can't read record to be removed");
    5652               0 :     row_info->dfile.file= old_file;
    5653               0 :     DBUG_RETURN(1);
    5654                 :   }
    5655               0 :   row_info->cur_row.lastpos= key_info->cur_row.lastpos;
    5656                 : 
    5657               0 :   for (i=0 ; i < sort_info->current_key ; i++)
    5658                 :   {
    5659                 :     MARIA_KEY tmp_key;
    5660               0 :     (*key_info->s->keyinfo[i].make_key)(key_info, &tmp_key, i, key,
    5661                 :                                         sort_param->record,
    5662                 :                                         key_info->cur_row.lastpos, 0);
    5663               0 :     if (_ma_ck_delete(key_info, &tmp_key))
    5664                 :     {
    5665               0 :       _ma_check_print_error(param,
    5666                 :                             "Can't delete key %d from record to be removed",
    5667                 :                             i+1);
    5668               0 :       row_info->dfile.file= old_file;
    5669               0 :       DBUG_RETURN(1);
    5670                 :     }
    5671                 :   }
    5672               0 :   if (sort_param->calc_checksum)
    5673               0 :     param->glob_crc-=(*key_info->s->calc_check_checksum)(key_info,
    5674                 :                                                          sort_param->record);
    5675               0 :   error= (*row_info->s->delete_record)(row_info, sort_param->record);
    5676               0 :   if (error)
    5677               0 :     _ma_check_print_error(param,"Got error %d when deleting record",
    5678                 :                           my_errno);
    5679               0 :   row_info->dfile.file= old_file;           /* restore actual value */
    5680               0 :   row_info->s->state.state.records--;
    5681               0 :   DBUG_RETURN(error);
    5682                 : } /* sort_delete_record */
    5683                 : 
    5684                 : 
    5685                 : /* Fix all pending blocks and flush everything to disk */
    5686                 : 
    5687                 : int _ma_flush_pending_blocks(MARIA_SORT_PARAM *sort_param)
    5688               0 : {
    5689                 :   uint nod_flag,length;
    5690                 :   my_off_t filepos,key_file_length;
    5691                 :   SORT_KEY_BLOCKS *key_block;
    5692               0 :   MARIA_SORT_INFO *sort_info= sort_param->sort_info;
    5693               0 :   myf myf_rw=sort_info->param->myf_rw;
    5694               0 :   MARIA_HA *info=sort_info->info;
    5695               0 :   MARIA_KEYDEF *keyinfo=sort_param->keyinfo;
    5696               0 :   MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
    5697               0 :   DBUG_ENTER("_ma_flush_pending_blocks");
    5698                 : 
    5699               0 :   filepos= HA_OFFSET_ERROR;                     /* if empty file */
    5700               0 :   nod_flag=0;
    5701               0 :   for (key_block=sort_info->key_block ; key_block->inited ; key_block++)
    5702                 :   {
    5703               0 :     key_block->inited=0;
    5704               0 :     length= _ma_get_page_used(info->s, key_block->buff);
    5705               0 :     if (nod_flag)
    5706               0 :       _ma_kpointer(info,key_block->end_pos,filepos);
    5707               0 :     key_file_length= info->s->state.state.key_file_length;
    5708               0 :     bzero(key_block->buff+length, keyinfo->block_length-length);
    5709               0 :     if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
    5710                 :         HA_OFFSET_ERROR)
    5711               0 :       goto err;
    5712                 : 
    5713                 :     /* If we read the page from the key cache, we have to write it back */
    5714               0 :     if (page_link->changed)
    5715                 :     {
    5716                 :       MARIA_PAGE page;
    5717               0 :       pop_dynamic(&info->pinned_pages);
    5718                 : 
    5719               0 :       _ma_page_setup(&page, info, keyinfo, filepos, key_block->buff);
    5720               0 :       if (_ma_write_keypage(&page, PAGECACHE_LOCK_WRITE_UNLOCK,
    5721                 :                             DFLT_INIT_HITS))
    5722                 :         goto err;
    5723                 :     }
    5724                 :     else
    5725                 :     {
    5726               0 :       put_crc(key_block->buff, filepos, info->s);
    5727               0 :       if (my_pwrite(info->s->kfile.file, key_block->buff,
    5728                 :                     (uint) keyinfo->block_length,filepos, myf_rw))
    5729               0 :         goto err;
    5730                 :     }
    5731               0 :     DBUG_DUMP("buff",key_block->buff,length);
    5732               0 :     nod_flag=1;
    5733                 :   }
    5734               0 :   info->s->state.key_root[sort_param->key]=filepos; /* Last is root for tree */
    5735               0 :   _ma_fast_unlock_key_del(info);
    5736               0 :   DBUG_RETURN(0);
    5737                 : 
    5738               0 : err:
    5739               0 :   _ma_fast_unlock_key_del(info);
    5740               0 :   DBUG_RETURN(1);
    5741                 : } /* _ma_flush_pending_blocks */
    5742                 : 
    5743                 :         /* alloc space and pointers for key_blocks */
    5744                 : 
    5745                 : static SORT_KEY_BLOCKS *alloc_key_blocks(HA_CHECK *param, uint blocks,
    5746                 :                                          uint buffer_length)
    5747               0 : {
    5748                 :   reg1 uint i;
    5749                 :   SORT_KEY_BLOCKS *block;
    5750               0 :   DBUG_ENTER("alloc_key_blocks");
    5751                 : 
    5752               0 :   if (!(block= (SORT_KEY_BLOCKS*) my_malloc((sizeof(SORT_KEY_BLOCKS)+
    5753                 :                                              buffer_length+IO_SIZE)*blocks,
    5754                 :                                             MYF(0))))
    5755                 :   {
    5756               0 :     _ma_check_print_error(param,"Not enough memory for sort-key-blocks");
    5757               0 :     return(0);
    5758                 :   }
    5759               0 :   for (i=0 ; i < blocks ; i++)
    5760                 :   {
    5761               0 :     block[i].inited=0;
    5762               0 :     block[i].buff= (uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
    5763                 :   }
    5764               0 :   DBUG_RETURN(block);
    5765                 : } /* alloc_key_blocks */
    5766                 : 
    5767                 : 
    5768                 :         /* Check if file is almost full */
    5769                 : 
    5770                 : int maria_test_if_almost_full(MARIA_HA *info)
    5771               0 : {
    5772               0 :   MARIA_SHARE *share= info->s;
    5773                 : 
    5774               0 :   if (share->options & HA_OPTION_COMPRESS_RECORD)
    5775               0 :     return 0;
    5776               0 :   return my_seek(share->kfile.file, 0L, MY_SEEK_END,
    5777                 :                  MYF(MY_THREADSAFE))/10*9 >
    5778                 :     (my_off_t) share->base.max_key_file_length ||
    5779                 :     my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 >
    5780                 :     (my_off_t) share->base.max_data_file_length;
    5781                 : }
    5782                 : 
    5783                 : 
    5784                 : /* Recreate table with bigger more alloced record-data */
    5785                 : 
    5786                 : int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
    5787               0 : {
    5788                 :   int error;
    5789                 :   MARIA_HA info;
    5790                 :   MARIA_SHARE share;
    5791                 :   MARIA_KEYDEF *keyinfo,*key,*key_end;
    5792                 :   HA_KEYSEG *keysegs,*keyseg;
    5793                 :   MARIA_COLUMNDEF *columndef,*column,*end;
    5794                 :   MARIA_UNIQUEDEF *uniquedef,*u_ptr,*u_end;
    5795                 :   MARIA_STATUS_INFO status_info;
    5796                 :   uint unpack,key_parts;
    5797                 :   ha_rows max_records;
    5798                 :   ulonglong file_length,tmp_length;
    5799                 :   MARIA_CREATE_INFO create_info;
    5800               0 :   DBUG_ENTER("maria_recreate_table");
    5801                 : 
    5802               0 :   error=1;                                      /* Default error */
    5803               0 :   info= **org_info;
    5804               0 :   status_info= (*org_info)->state[0];
    5805               0 :   info.state= &status_info;
    5806               0 :   share= *(*org_info)->s;
    5807               0 :   unpack= ((share.data_file_type == COMPRESSED_RECORD) &&
    5808                 :            (param->testflag & T_UNPACK));
    5809               0 :   if (!(keyinfo=(MARIA_KEYDEF*) my_alloca(sizeof(MARIA_KEYDEF) *
    5810                 :                                           share.base.keys)))
    5811               0 :     DBUG_RETURN(0);
    5812               0 :   memcpy((uchar*) keyinfo,(uchar*) share.keyinfo,
    5813                 :          (size_t) (sizeof(MARIA_KEYDEF)*share.base.keys));
    5814                 : 
    5815               0 :   key_parts= share.base.all_key_parts;
    5816               0 :   if (!(keysegs=(HA_KEYSEG*) my_alloca(sizeof(HA_KEYSEG)*
    5817                 :                                        (key_parts+share.base.keys))))
    5818                 :   {
    5819                 :     my_afree(keyinfo);
    5820               0 :     DBUG_RETURN(1);
    5821                 :   }
    5822               0 :   if (!(columndef=(MARIA_COLUMNDEF*)
    5823                 :         my_alloca(sizeof(MARIA_COLUMNDEF)*(share.base.fields+1))))
    5824                 :   {
    5825                 :     my_afree(keyinfo);
    5826                 :     my_afree(keysegs);
    5827               0 :     DBUG_RETURN(1);
    5828                 :   }
    5829               0 :   if (!(uniquedef=(MARIA_UNIQUEDEF*)
    5830                 :         my_alloca(sizeof(MARIA_UNIQUEDEF)*(share.state.header.uniques+1))))
    5831                 :   {
    5832                 :     my_afree(columndef);
    5833                 :     my_afree(keyinfo);
    5834                 :     my_afree(keysegs);
    5835               0 :     DBUG_RETURN(1);
    5836                 :   }
    5837                 : 
    5838                 :   /* Copy the column definitions in their original order */
    5839               0 :   for (column= share.columndef, end= share.columndef+share.base.fields;
    5840               0 :        column != end ;
    5841               0 :        column++)
    5842               0 :     columndef[column->column_nr]= *column;
    5843                 : 
    5844                 :   /* Change the new key to point at the saved key segments */
    5845               0 :   memcpy((uchar*) keysegs,(uchar*) share.keyparts,
    5846                 :          (size_t) (sizeof(HA_KEYSEG)*(key_parts+share.base.keys+
    5847                 :                                       share.state.header.uniques)));
    5848               0 :   keyseg=keysegs;
    5849               0 :   for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
    5850                 :   {
    5851               0 :     key->seg=keyseg;
    5852               0 :     for (; keyseg->type ; keyseg++)
    5853                 :     {
    5854               0 :       if (param->language)
    5855               0 :         keyseg->language=param->language; /* change language */
    5856                 :     }
    5857               0 :     keyseg++;                                   /* Skip end pointer */
    5858                 :   }
    5859                 : 
    5860                 :   /*
    5861                 :     Copy the unique definitions and change them to point at the new key
    5862                 :     segments
    5863                 :   */
    5864               0 :   memcpy((uchar*) uniquedef,(uchar*) share.uniqueinfo,
    5865                 :          (size_t) (sizeof(MARIA_UNIQUEDEF)*(share.state.header.uniques)));
    5866               0 :   for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques;
    5867               0 :        u_ptr != u_end ; u_ptr++)
    5868                 :   {
    5869               0 :     u_ptr->seg=keyseg;
    5870               0 :     keyseg+=u_ptr->keysegs+1;
    5871                 :   }
    5872                 : 
    5873               0 :   file_length=(ulonglong) my_seek(info.dfile.file, 0L, MY_SEEK_END, MYF(0));
    5874               0 :   if (share.options & HA_OPTION_COMPRESS_RECORD)
    5875               0 :     share.base.records=max_records=info.state->records;
    5876               0 :   else if (share.base.min_pack_length)
    5877               0 :     max_records=(ha_rows) (file_length / share.base.min_pack_length);
    5878                 :   else
    5879               0 :     max_records=0;
    5880               0 :   share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
    5881                 : 
    5882               0 :   tmp_length= file_length+file_length/10;
    5883               0 :   set_if_bigger(file_length,param->max_data_file_length);
    5884               0 :   set_if_bigger(file_length,tmp_length);
    5885               0 :   set_if_bigger(file_length,(ulonglong) share.base.max_data_file_length);
    5886                 : 
    5887               0 :   VOID(maria_close(*org_info));
    5888                 : 
    5889               0 :   bzero((char*) &create_info,sizeof(create_info));
    5890               0 :   create_info.max_rows=max(max_records,share.base.records);
    5891               0 :   create_info.reloc_rows=share.base.reloc;
    5892               0 :   create_info.old_options=(share.options |
    5893                 :                            (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));
    5894                 : 
    5895               0 :   create_info.data_file_length=file_length;
    5896               0 :   create_info.auto_increment=share.state.auto_increment;
    5897               0 :   create_info.language = (param->language ? param->language :
    5898                 :                           share.state.header.language);
    5899               0 :   create_info.key_file_length=  status_info.key_file_length;
    5900               0 :   create_info.org_data_file_type= ((enum data_file_type)
    5901                 :                                    share.state.header.org_data_file_type);
    5902                 : 
    5903                 :   /*
    5904                 :     Allow for creating an auto_increment key. This has an effect only if
    5905                 :     an auto_increment key exists in the original table.
    5906                 :   */
    5907               0 :   create_info.with_auto_increment= TRUE;
    5908               0 :   create_info.null_bytes= share.base.null_bytes;
    5909               0 :   create_info.transactional= share.base.born_transactional;
    5910                 : 
    5911                 :   /*
    5912                 :     We don't have to handle symlinks here because we are using
    5913                 :     HA_DONT_TOUCH_DATA
    5914                 :   */
    5915               0 :   if (maria_create(filename, share.data_file_type,
    5916                 :                    share.base.keys - share.state.header.uniques,
    5917                 :                    keyinfo, share.base.fields, columndef,
    5918                 :                    share.state.header.uniques, uniquedef,
    5919                 :                    &create_info,
    5920                 :                    HA_DONT_TOUCH_DATA))
    5921                 :   {
    5922               0 :     _ma_check_print_error(param,
    5923                 :                           "Got error %d when trying to recreate indexfile",
    5924                 :                           my_errno);
    5925               0 :     goto end;
    5926                 :   }
    5927               0 :   *org_info= maria_open(filename,O_RDWR,
    5928                 :                         (HA_OPEN_FOR_REPAIR |
    5929                 :                          ((param->testflag & T_WAIT_FOREVER) ?
    5930                 :                           HA_OPEN_WAIT_IF_LOCKED :
    5931                 :                           (param->testflag & T_DESCRIPT) ?
    5932                 :                           HA_OPEN_IGNORE_IF_LOCKED :
    5933                 :                           HA_OPEN_ABORT_IF_LOCKED)));
    5934               0 :   if (!*org_info)
    5935                 :   {
    5936               0 :     _ma_check_print_error(param,
    5937                 :                           "Got error %d when trying to open re-created "
    5938                 :                           "indexfile", my_errno);
    5939               0 :     goto end;
    5940                 :   }
    5941                 :   /* We are modifing */
    5942               0 :   (*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
    5943               0 :   VOID(_ma_readinfo(*org_info,F_WRLCK,0));
    5944               0 :   (*org_info)->s->state.state.records= info.state->records;
    5945               0 :   if (share.state.create_time)
    5946               0 :     (*org_info)->s->state.create_time=share.state.create_time;
    5947                 : #ifdef EXTERNAL_LOCKING
    5948                 :   (*org_info)->s->state.unique= (*org_info)->this_unique= share.state.unique;
    5949                 : #endif
    5950               0 :   (*org_info)->s->state.state.checksum= info.state->checksum;
    5951               0 :   (*org_info)->s->state.state.del= info.state->del;
    5952               0 :   (*org_info)->s->state.dellink= share.state.dellink;
    5953               0 :   (*org_info)->s->state.state.empty= info.state->empty;
    5954               0 :   (*org_info)->s->state.state.data_file_length= info.state->data_file_length;
    5955               0 :   *(*org_info)->state= (*org_info)->s->state.state;
    5956               0 :   if (maria_update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
    5957                 :                               UPDATE_OPEN_COUNT))
    5958               0 :     goto end;
    5959               0 :   error=0;
    5960               0 : end:
    5961                 :   my_afree(uniquedef);
    5962                 :   my_afree(keyinfo);
    5963                 :   my_afree(columndef);
    5964                 :   my_afree(keysegs);
    5965               0 :   DBUG_RETURN(error);
    5966                 : }
    5967                 : 
    5968                 : 
    5969                 :         /* write suffix to data file if neaded */
    5970                 : 
    5971                 : int maria_write_data_suffix(MARIA_SORT_INFO *sort_info, my_bool fix_datafile)
    5972               0 : {
    5973               0 :   MARIA_HA *info=sort_info->new_info;
    5974                 : 
    5975               0 :   if (info->s->data_file_type == COMPRESSED_RECORD && fix_datafile)
    5976                 :   {
    5977                 :     uchar buff[MEMMAP_EXTRA_MARGIN];
    5978               0 :     bzero(buff,sizeof(buff));
    5979               0 :     if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
    5980                 :     {
    5981               0 :       _ma_check_print_error(sort_info->param,
    5982                 :                            "%d when writing to datafile",my_errno);
    5983               0 :       return 1;
    5984                 :     }
    5985               0 :     sort_info->param->read_cache.end_of_file+=sizeof(buff);
    5986                 :   }
    5987               0 :   return 0;
    5988                 : }
    5989                 : 
    5990                 : 
    5991                 : /* Update state and maria_chk time of indexfile */
    5992                 : 
    5993                 : int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
    5994               0 : {
    5995               0 :   MARIA_SHARE *share= info->s;
    5996               0 :   DBUG_ENTER("maria_update_state_info");
    5997                 : 
    5998               0 :   if (update & UPDATE_OPEN_COUNT)
    5999                 :   {
    6000               0 :     share->state.open_count=0;
    6001               0 :     share->global_changed=0;
    6002                 :   }
    6003               0 :   if (update & UPDATE_STAT)
    6004                 :   {
    6005               0 :     uint i, key_parts= mi_uint2korr(share->state.header.key_parts);
    6006               0 :     share->state.records_at_analyze= share->state.state.records;
    6007               0 :     share->state.changed&= ~STATE_NOT_ANALYZED;
    6008               0 :     if (share->state.state.records)
    6009                 :     {
    6010               0 :       for (i=0; i<key_parts; i++)
    6011                 :       {
    6012               0 :         if (!(share->state.rec_per_key_part[i]=param->new_rec_per_key_part[i]))
    6013               0 :           share->state.changed|= STATE_NOT_ANALYZED;
    6014                 :       }
    6015                 :     }
    6016                 :   }
    6017               0 :   if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC))
    6018                 :   {
    6019               0 :     if (update & UPDATE_TIME)
    6020                 :     {
    6021               0 :       share->state.check_time= (long) time((time_t*) 0);
    6022               0 :       if (!share->state.create_time)
    6023               0 :         share->state.create_time= share->state.check_time;
    6024                 :     }
    6025               0 :     if (_ma_state_info_write(share,
    6026                 :                              MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
    6027                 :                              MA_STATE_INFO_WRITE_FULL_INFO))
    6028               0 :       goto err;
    6029               0 :     share->changed=0;
    6030                 :   }
    6031                 :   {                                             /* Force update of status */
    6032                 :     int error;
    6033               0 :     uint r_locks=share->r_locks,w_locks=share->w_locks;
    6034               0 :     share->r_locks= share->w_locks= share->tot_locks= 0;
    6035               0 :     error= _ma_writeinfo(info,WRITEINFO_NO_UNLOCK);
    6036               0 :     share->r_locks=r_locks;
    6037               0 :     share->w_locks=w_locks;
    6038               0 :     share->tot_locks=r_locks+w_locks;
    6039               0 :     if (!error)
    6040               0 :       DBUG_RETURN(0);
    6041                 :   }
    6042               0 : err:
    6043               0 :   _ma_check_print_error(param,"%d when updating keyfile",my_errno);
    6044               0 :   DBUG_RETURN(1);
    6045                 : }
    6046                 : 
    6047                 : /*
    6048                 :   Update auto increment value for a table
    6049                 :   When setting the 'repair_only' flag we only want to change the
    6050                 :   old auto_increment value if its wrong (smaller than some given key).
    6051                 :   The reason is that we shouldn't change the auto_increment value
    6052                 :   for a table without good reason when only doing a repair; If the
    6053                 :   user have inserted and deleted rows, the auto_increment value
    6054                 :   may be bigger than the biggest current row and this is ok.
    6055                 : 
    6056                 :   If repair_only is not set, we will update the flag to the value in
    6057                 :   param->auto_increment is bigger than the biggest key.
    6058                 : */
    6059                 : 
    6060                 : void _ma_update_auto_increment_key(HA_CHECK *param, MARIA_HA *info,
    6061                 :                                    my_bool repair_only)
    6062               0 : {
    6063               0 :   MARIA_SHARE *share= info->s;
    6064                 :   uchar *record;
    6065               0 :   DBUG_ENTER("update_auto_increment_key");
    6066                 : 
    6067               0 :   if (!share->base.auto_key ||
    6068                 :       ! maria_is_key_active(share->state.key_map, share->base.auto_key - 1))
    6069                 :   {
    6070               0 :     if (!(param->testflag & T_VERY_SILENT))
    6071               0 :       _ma_check_print_info(param,
    6072                 :                           "Table: %s doesn't have an auto increment key\n",
    6073                 :                           param->isam_file_name);
    6074               0 :     DBUG_VOID_RETURN;
    6075                 :   }
    6076               0 :   if (!(param->testflag & T_SILENT) &&
    6077                 :       !(param->testflag & T_REP))
    6078               0 :     printf("Updating MARIA file: %s\n", param->isam_file_name);
    6079                 :   /*
    6080                 :     We have to use an allocated buffer instead of info->rec_buff as
    6081                 :     _ma_put_key_in_record() may use info->rec_buff
    6082                 :   */
    6083               0 :   if (!(record= (uchar*) my_malloc((size_t) share->base.default_rec_buff_size,
    6084                 :                                    MYF(0))))
    6085                 :   {
    6086               0 :     _ma_check_print_error(param,"Not enough memory for extra record");
    6087               0 :     DBUG_VOID_RETURN;
    6088                 :   }
    6089                 : 
    6090               0 :   maria_extra(info,HA_EXTRA_KEYREAD,0);
    6091               0 :   if (maria_rlast(info, record, share->base.auto_key-1))
    6092                 :   {
    6093               0 :     if (my_errno != HA_ERR_END_OF_FILE)
    6094                 :     {
    6095               0 :       maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
    6096               0 :       my_free((char*) record, MYF(0));
    6097               0 :       _ma_check_print_error(param,"%d when reading last record",my_errno);
    6098               0 :       DBUG_VOID_RETURN;
    6099                 :     }
    6100               0 :     if (!repair_only)
    6101               0 :       share->state.auto_increment=param->auto_increment_value;
    6102                 :   }
    6103                 :   else
    6104                 :   {
    6105               0 :     const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
    6106                 :     ulonglong auto_increment=
    6107               0 :       ma_retrieve_auto_increment(record + keyseg->start, keyseg->type);
    6108               0 :     set_if_bigger(share->state.auto_increment,auto_increment);
    6109               0 :     if (!repair_only)
    6110               0 :       set_if_bigger(share->state.auto_increment, param->auto_increment_value);
    6111                 :   }
    6112               0 :   maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
    6113               0 :   my_free((char*) record, MYF(0));
    6114               0 :   maria_update_state_info(param, info, UPDATE_AUTO_INC);
    6115               0 :   DBUG_VOID_RETURN;
    6116                 : }
    6117                 : 
    6118                 : 
    6119                 : /*
    6120                 :   Update statistics for each part of an index
    6121                 : 
    6122                 :   SYNOPSIS
    6123                 :     maria_update_key_parts()
    6124                 :       keyinfo           IN  Index information (only key->keysegs used)
    6125                 :       rec_per_key_part  OUT Store statistics here
    6126                 :       unique            IN  Array of (#distinct tuples)
    6127                 :       notnull_tuples    IN  Array of (#tuples), or NULL
    6128                 :       records               Number of records in the table
    6129                 : 
    6130                 :   DESCRIPTION
    6131                 :     This function is called produce index statistics values from unique and
    6132                 :     notnull_tuples arrays after these arrays were produced with sequential
    6133                 :     index scan (the scan is done in two places: chk_index() and
    6134                 :     sort_key_write()).
    6135                 : 
    6136                 :     This function handles all 3 index statistics collection methods.
    6137                 : 
    6138                 :     Unique is an array:
    6139                 :       unique[0]= (#different values of {keypart1}) - 1
    6140                 :       unique[1]= (#different values of {keypart1,keypart2} tuple)-unique[0]-1
    6141                 :       ...
    6142                 : 
    6143                 :     For MI_STATS_METHOD_IGNORE_NULLS method, notnull_tuples is an array too:
    6144                 :       notnull_tuples[0]= (#of {keypart1} tuples such that keypart1 is not NULL)
    6145                 :       notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all
    6146                 :                           keypart{i} are not NULL)
    6147                 :       ...
    6148                 :     For all other statistics collection methods notnull_tuples==NULL.
    6149                 : 
    6150                 :     Output is an array:
    6151                 :     rec_per_key_part[k] =
    6152                 :      = E(#records in the table such that keypart_1=c_1 AND ... AND
    6153                 :          keypart_k=c_k for arbitrary constants c_1 ... c_k)
    6154                 : 
    6155                 :      = {assuming that values have uniform distribution and index contains all
    6156                 :         tuples from the domain (or that {c_1, ..., c_k} tuple is choosen from
    6157                 :         index tuples}
    6158                 : 
    6159                 :      = #tuples-in-the-index / #distinct-tuples-in-the-index.
    6160                 : 
    6161                 :     The #tuples-in-the-index and #distinct-tuples-in-the-index have different
    6162                 :     meaning depending on which statistics collection method is used:
    6163                 : 
    6164                 :     MI_STATS_METHOD_*  how are nulls compared?  which tuples are counted?
    6165                 :      NULLS_EQUAL            NULL == NULL           all tuples in table
    6166                 :      NULLS_NOT_EQUAL        NULL != NULL           all tuples in table
    6167                 :      IGNORE_NULLS               n/a             tuples that don't have NULLs
    6168                 : */
    6169                 : 
    6170                 : void maria_update_key_parts(MARIA_KEYDEF *keyinfo, double *rec_per_key_part,
    6171                 :                       ulonglong *unique, ulonglong *notnull,
    6172                 :                       ulonglong records)
    6173               0 : {
    6174               0 :   ulonglong count=0, unique_tuples;
    6175               0 :   ulonglong tuples= records;
    6176                 :   uint parts;
    6177                 :   double tmp;
    6178               0 :   for (parts=0 ; parts < keyinfo->keysegs  ; parts++)
    6179                 :   {
    6180               0 :     count+=unique[parts];
    6181               0 :     unique_tuples= count + 1;
    6182               0 :     if (notnull)
    6183                 :     {
    6184               0 :       tuples= notnull[parts];
    6185                 :       /*
    6186                 :         #(unique_tuples not counting tuples with NULLs) =
    6187                 :           #(unique_tuples counting tuples with NULLs as different) -
    6188                 :           #(tuples with NULLs)
    6189                 :       */
    6190               0 :       unique_tuples -= (records - notnull[parts]);
    6191                 :     }
    6192                 : 
    6193               0 :     if (unique_tuples == 0)
    6194               0 :       tmp= 1;
    6195               0 :     else if (count == 0)
    6196               0 :       tmp= ulonglong2double(tuples); /* 1 unique tuple */
    6197                 :     else
    6198               0 :       tmp= ulonglong2double(tuples) / ulonglong2double(unique_tuples);
    6199                 : 
    6200                 :     /*
    6201                 :       for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
    6202                 :       let's ensure it is not
    6203                 :     */
    6204               0 :     set_if_bigger(tmp,1);
    6205                 : 
    6206               0 :     *rec_per_key_part++= tmp;
    6207                 :   }
    6208                 : }
    6209                 : 
    6210                 : 
    6211                 : static ha_checksum maria_byte_checksum(const uchar *buf, uint length)
    6212               0 : {
    6213                 :   ha_checksum crc;
    6214               0 :   const uchar *end=buf+length;
    6215               0 :   for (crc=0; buf != end; buf++)
    6216               0 :     crc=((crc << 1) + *buf) +
    6217                 :       test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1)));
    6218               0 :   return crc;
    6219                 : }
    6220                 : 
    6221                 : static my_bool maria_too_big_key_for_sort(MARIA_KEYDEF *key, ha_rows rows)
    6222               0 : {
    6223               0 :   uint key_maxlength=key->maxlength;
    6224               0 :   if (key->flag & HA_FULLTEXT)
    6225                 :   {
    6226                 :     uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
    6227               0 :                                   key->seg->charset->mbmaxlen;
    6228               0 :     key_maxlength+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
    6229                 :   }
    6230               0 :   return (key->flag & HA_SPATIAL) ||
    6231                 :           (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) &&
    6232                 :           ((ulonglong) rows * key_maxlength >
    6233                 :            (ulonglong) maria_max_temp_length));
    6234                 : }
    6235                 : 
    6236                 : /*
    6237                 :   Deactivate all not unique index that can be recreated fast
    6238                 :   These include packed keys on which sorting will use more temporary
    6239                 :   space than the max allowed file length or for which the unpacked keys
    6240                 :   will take much more space than packed keys.
    6241                 :   Note that 'rows' may be zero for the case when we don't know how many
    6242                 :   rows we will put into the file.
    6243                 :  */
    6244                 : 
    6245                 : void maria_disable_non_unique_index(MARIA_HA *info, ha_rows rows)
    6246               0 : {
    6247               0 :   MARIA_SHARE *share= info->s;
    6248               0 :   MARIA_KEYDEF    *key=share->keyinfo;
    6249                 :   uint          i;
    6250                 : 
    6251               0 :   DBUG_ASSERT(share->state.state.records == 0 &&
    6252                 :               (!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES));
    6253               0 :   for (i=0 ; i < share->base.keys ; i++,key++)
    6254                 :   {
    6255               0 :     if (!(key->flag &
    6256                 :           (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY | HA_RTREE_INDEX)) &&
    6257                 :         ! maria_too_big_key_for_sort(key,rows) && share->base.auto_key != i+1)
    6258                 :     {
    6259               0 :       maria_clear_key_active(share->state.key_map, i);
    6260               0 :       info->update|= HA_STATE_CHANGED;
    6261                 :     }
    6262                 :   }
    6263                 : }
    6264                 : 
    6265                 : 
    6266                 : /*
    6267                 :   Return TRUE if we can use repair by sorting
    6268                 :   One can set the force argument to force to use sorting
    6269                 :   even if the temporary file would be quite big!
    6270                 : */
    6271                 : 
    6272                 : my_bool maria_test_if_sort_rep(MARIA_HA *info, ha_rows rows,
    6273                 :                                ulonglong key_map, my_bool force)
    6274               0 : {
    6275               0 :   MARIA_SHARE *share= info->s;
    6276               0 :   MARIA_KEYDEF *key=share->keyinfo;
    6277                 :   uint i;
    6278                 : 
    6279                 :   /*
    6280                 :     maria_repair_by_sort only works if we have at least one key. If we don't
    6281                 :     have any keys, we should use the normal repair.
    6282                 :   */
    6283               0 :   if (! maria_is_any_key_active(key_map))
    6284               0 :     return FALSE;                               /* Can't use sort */
    6285               0 :   for (i=0 ; i < share->base.keys ; i++,key++)
    6286                 :   {
    6287               0 :     if (!force && maria_too_big_key_for_sort(key,rows))
    6288               0 :       return FALSE;
    6289                 :   }
    6290               0 :   return TRUE;
    6291                 : }
    6292                 : 
    6293                 : 
    6294                 : /**
    6295                 :    @brief Create a new handle for manipulation the new record file
    6296                 : 
    6297                 :    @note
    6298                 :    It's ok for Recovery to have two MARIA_SHARE on the same index file
    6299                 :    because the one we create here is not transactional
    6300                 : */
    6301                 : 
    6302                 : static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file)
    6303               0 : {
    6304                 : 
    6305               0 :   MARIA_SORT_INFO *sort_info= param->sort_info;
    6306               0 :   MARIA_HA *info= sort_info->info;
    6307                 :   MARIA_HA *new_info;
    6308               0 :   DBUG_ENTER("create_new_data_handle");
    6309                 : 
    6310               0 :   if (!(sort_info->new_info= maria_open(info->s->open_file_name.str, O_RDWR,
    6311                 :                                         HA_OPEN_COPY | HA_OPEN_FOR_REPAIR)))
    6312               0 :     DBUG_RETURN(1);
    6313                 : 
    6314               0 :   new_info= sort_info->new_info;
    6315               0 :   _ma_bitmap_set_pagecache_callbacks(&new_info->s->bitmap.file,
    6316                 :                                      new_info->s);
    6317               0 :   _ma_set_data_pagecache_callbacks(&new_info->dfile, new_info->s);
    6318               0 :   change_data_file_descriptor(new_info, new_file);
    6319               0 :   maria_lock_database(new_info, F_EXTRA_LCK);
    6320               0 :   if ((sort_info->param->testflag & T_UNPACK) &&
    6321                 :       info->s->data_file_type == COMPRESSED_RECORD)
    6322                 :   {
    6323               0 :     (*new_info->s->once_end)(new_info->s);
    6324               0 :     (*new_info->s->end)(new_info);
    6325               0 :     restore_data_file_type(new_info->s);
    6326               0 :     _ma_setup_functions(new_info->s);
    6327               0 :     if ((*new_info->s->once_init)(new_info->s, new_file) ||
    6328                 :         (*new_info->s->init)(new_info))
    6329               0 :       DBUG_RETURN(1);
    6330                 :   }
    6331               0 :   _ma_reset_status(new_info);
    6332               0 :   if (_ma_initialize_data_file(new_info->s, new_file))
    6333               0 :     DBUG_RETURN(1);
    6334                 : 
    6335                 :   /* Take into account any bitmap page created above: */
    6336               0 :   param->filepos= new_info->s->state.state.data_file_length;
    6337                 : 
    6338                 :   /* Use new virtual functions for key generation */
    6339               0 :   info->s->keypos_to_recpos= new_info->s->keypos_to_recpos;
    6340               0 :   info->s->recpos_to_keypos= new_info->s->recpos_to_keypos;
    6341               0 :   DBUG_RETURN(0);
    6342                 : }
    6343                 : 
    6344                 : 
    6345                 : static void
    6346                 : set_data_file_type(MARIA_SORT_INFO *sort_info, MARIA_SHARE *share)
    6347               0 : {
    6348               0 :   if ((sort_info->new_data_file_type=share->data_file_type) ==
    6349                 :       COMPRESSED_RECORD && sort_info->param->testflag & T_UNPACK)
    6350                 :   {
    6351                 :     MARIA_SHARE tmp;
    6352               0 :     sort_info->new_data_file_type= share->state.header.org_data_file_type;
    6353                 :     /* Set delete_function for sort_delete_record() */
    6354               0 :     tmp= *share;
    6355               0 :     tmp.state.header.data_file_type= tmp.state.header.org_data_file_type;
    6356               0 :     tmp.options= ~HA_OPTION_COMPRESS_RECORD;
    6357               0 :     _ma_setup_functions(&tmp);
    6358               0 :     share->delete_record=tmp.delete_record;
    6359                 :   }
    6360                 : }
    6361                 : 
    6362                 : static void restore_data_file_type(MARIA_SHARE *share)
    6363               0 : {
    6364                 :   MARIA_SHARE tmp_share;
    6365               0 :   share->options&= ~HA_OPTION_COMPRESS_RECORD;
    6366               0 :   mi_int2store(share->state.header.options,share->options);
    6367               0 :   share->state.header.data_file_type=
    6368                 :     share->state.header.org_data_file_type;
    6369               0 :   share->data_file_type= share->state.header.data_file_type;
    6370               0 :   share->pack.header_length= 0;
    6371                 : 
    6372                 :   /* Use new virtual functions for key generation */
    6373               0 :   tmp_share= *share;
    6374               0 :   _ma_setup_functions(&tmp_share);
    6375               0 :   share->keypos_to_recpos= tmp_share.keypos_to_recpos;
    6376               0 :   share->recpos_to_keypos= tmp_share.recpos_to_keypos;
    6377                 : }
    6378                 : 
    6379                 : 
    6380                 : static void change_data_file_descriptor(MARIA_HA *info, File new_file)
    6381               0 : {
    6382               0 :   my_close(info->dfile.file, MYF(MY_WME));
    6383               0 :   info->dfile.file= info->s->bitmap.file.file= new_file;
    6384               0 :   _ma_bitmap_reset_cache(info->s);
    6385                 : }
    6386                 : 
    6387                 : 
    6388                 : /**
    6389                 :    @brief Mark the data file to not be used
    6390                 : 
    6391                 :    @note
    6392                 :    This is used in repair when we want to ensure the handler will not
    6393                 :    write anything to the data file anymore
    6394                 : */
    6395                 : 
    6396                 : static void unuse_data_file_descriptor(MARIA_HA *info)
    6397               0 : {
    6398               0 :   info->dfile.file= info->s->bitmap.file.file= -1;
    6399               0 :   _ma_bitmap_reset_cache(info->s);
    6400                 : }
    6401                 : 
    6402                 : 
    6403                 : /*
    6404                 :   Copy all states that has to do with the data file
    6405                 : 
    6406                 :   NOTES
    6407                 :     This is done to copy the state from the data file generated from
    6408                 :     repair to the original handler
    6409                 : */
    6410                 : 
    6411                 : static void copy_data_file_state(MARIA_STATE_INFO *to,
    6412                 :                                  MARIA_STATE_INFO *from)
    6413               0 : {
    6414               0 :   to->state.records=           from->state.records;
    6415               0 :   to->state.del=               from->state.del;
    6416               0 :   to->state.empty=             from->state.empty;
    6417               0 :   to->state.data_file_length=  from->state.data_file_length;
    6418               0 :   to->split=                   from->split;
    6419               0 :   to->dellink=                      from->dellink;
    6420               0 :   to->first_bitmap_with_space= from->first_bitmap_with_space;
    6421                 : }
    6422                 : 
    6423                 : 
    6424                 : /*
    6425                 :   Read 'safely' next record while scanning table.
    6426                 : 
    6427                 :   SYNOPSIS
    6428                 :     _ma_safe_scan_block_record()
    6429                 :     info                Maria handler
    6430                 :     record              Store found here
    6431                 : 
    6432                 :   NOTES
    6433                 :     - One must have called mi_scan() before this
    6434                 : 
    6435                 :     Differences compared to  _ma_scan_block_records() are:
    6436                 :     - We read all blocks, not only blocks marked by the bitmap to be safe
    6437                 :     - In case of errors, next read will read next record.
    6438                 :     - More sanity checks
    6439                 : 
    6440                 :   RETURN
    6441                 :     0   ok
    6442                 :     HA_ERR_END_OF_FILE  End of file
    6443                 :     #   error number
    6444                 : */
    6445                 : 
    6446                 : 
    6447                 : static int _ma_safe_scan_block_record(MARIA_SORT_INFO *sort_info,
    6448                 :                                       MARIA_HA *info, uchar *record)
    6449               0 : {
    6450               0 :   MARIA_SHARE *share= info->s;
    6451               0 :   MARIA_RECORD_POS record_pos= info->cur_row.nextpos;
    6452               0 :   pgcache_page_no_t page= sort_info->page;
    6453               0 :   DBUG_ENTER("_ma_safe_scan_block_record");
    6454                 : 
    6455                 :   for (;;)
    6456                 :   {
    6457                 :     /* Find next row in current page */
    6458               0 :     if (likely(record_pos < info->scan.number_of_rows))
    6459                 :     {
    6460                 :       uint length, offset;
    6461                 :       uchar *data, *end_of_data;
    6462                 :       char llbuff[22];
    6463                 : 
    6464               0 :       while (!(offset= uint2korr(info->scan.dir)))
    6465                 :       {
    6466               0 :         info->scan.dir-= DIR_ENTRY_SIZE;
    6467               0 :         record_pos++;
    6468               0 :         if (info->scan.dir < info->scan.dir_end)
    6469                 :         {
    6470               0 :           _ma_check_print_info(sort_info->param,
    6471                 :                                "Wrong directory on page %s",
    6472                 :                                llstr(page, llbuff));
    6473               0 :           goto read_next_page;
    6474                 :         }
    6475                 :       }
    6476                 :       /* found row */
    6477               0 :       info->cur_row.lastpos= info->scan.row_base_page + record_pos;
    6478               0 :       info->cur_row.nextpos= record_pos + 1;
    6479               0 :       data= info->scan.page_buff + offset;
    6480               0 :       length= uint2korr(info->scan.dir + 2);
    6481               0 :       end_of_data= data + length;
    6482               0 :       info->scan.dir-= DIR_ENTRY_SIZE;          /* Point to previous row */
    6483                 : 
    6484               0 :       if (end_of_data > info->scan.dir_end ||
    6485                 :           offset < PAGE_HEADER_SIZE || length < share->base.min_block_length)
    6486                 :       {
    6487               0 :         _ma_check_print_info(sort_info->param,
    6488                 :                              "Wrong directory entry %3u at page %s",
    6489                 :                              (uint) record_pos, llstr(page, llbuff));
    6490               0 :         record_pos++;
    6491               0 :         continue;
    6492                 :       }
    6493                 :       else
    6494                 :       {
    6495               0 :         DBUG_PRINT("info", ("rowid: %lu", (ulong) info->cur_row.lastpos));
    6496               0 :         DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data));
    6497                 :       }
    6498                 :     }
    6499                 : 
    6500               0 : read_next_page:
    6501                 :     /* Read until we find next head page */
    6502                 :     for (;;)
    6503                 :     {
    6504                 :       uint page_type;
    6505                 :       char llbuff[22];
    6506                 : 
    6507               0 :       sort_info->page++;                        /* In case of errors */
    6508               0 :       page++;
    6509               0 :       if (!(page % share->bitmap.pages_covered))
    6510                 :       {
    6511                 :         /* Skip bitmap */
    6512               0 :         page++;
    6513               0 :         sort_info->page++;
    6514                 :       }
    6515               0 :       if ((my_off_t) (page + 1) * share->block_size > sort_info->filelength)
    6516               0 :         DBUG_RETURN(HA_ERR_END_OF_FILE);
    6517               0 :       if (!(pagecache_read(share->pagecache,
    6518                 :                            &info->dfile,
    6519                 :                            page, 0, info->scan.page_buff,
    6520                 :                            PAGECACHE_READ_UNKNOWN_PAGE,
    6521                 :                            PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
    6522                 :       {
    6523               0 :         if (my_errno == HA_ERR_WRONG_CRC)
    6524                 :         {
    6525               0 :           _ma_check_print_info(sort_info->param,
    6526                 :                                "Wrong CRC on datapage at %s",
    6527                 :                                llstr(page, llbuff));
    6528               0 :           continue;
    6529                 :         }
    6530               0 :         DBUG_RETURN(my_errno);
    6531                 :       }
    6532               0 :       page_type= (info->scan.page_buff[PAGE_TYPE_OFFSET] &
    6533                 :                   PAGE_TYPE_MASK);
    6534               0 :       if (page_type == HEAD_PAGE)
    6535                 :       {
    6536               0 :         if ((info->scan.number_of_rows=
    6537                 :              (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) != 0)
    6538               0 :           break;
    6539               0 :         _ma_check_print_info(sort_info->param,
    6540                 :                              "Wrong head page at page %s",
    6541                 :                              llstr(page, llbuff));
    6542                 :       }
    6543               0 :       else if (page_type >= MAX_PAGE_TYPE)
    6544                 :       {
    6545               0 :         _ma_check_print_info(sort_info->param,
    6546                 :                              "Found wrong page type: %d at page %s",
    6547                 :                              page_type, llstr(page, llbuff));
    6548                 :       }
    6549                 :     }
    6550                 : 
    6551                 :     /* New head page */
    6552               0 :     info->scan.dir= (info->scan.page_buff + share->block_size -
    6553                 :                      PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE);
    6554               0 :     info->scan.dir_end= (info->scan.dir -
    6555                 :                          (info->scan.number_of_rows - 1) *
    6556                 :                          DIR_ENTRY_SIZE);
    6557               0 :     info->scan.row_base_page= ma_recordpos(page, 0);
    6558               0 :     record_pos= 0;
    6559                 :   }
    6560                 : }
    6561                 : 
    6562                 : 
    6563                 : /**
    6564                 :    @brief Writes a LOGREC_REPAIR_TABLE record and updates create_rename_lsn
    6565                 :    if needed (so that maria_read_log does not redo the repair).
    6566                 : 
    6567                 :    @param  param            description of the REPAIR operation
    6568                 :    @param  info             table
    6569                 : 
    6570                 :    @return Operation status
    6571                 :      @retval 0      ok
    6572                 :      @retval 1      error (disk problem)
    6573                 : */
    6574                 : 
    6575                 : my_bool write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info)
    6576               0 : {
    6577               0 :   MARIA_SHARE *share= info->s;
    6578                 :   /* in case this is maria_chk or recovery... */
    6579               0 :   if (translog_status == TRANSLOG_OK && !maria_in_recovery &&
    6580                 :       share->base.born_transactional)
    6581                 :   {
    6582               0 :     my_bool save_now_transactional= share->now_transactional;
    6583                 : 
    6584                 :     /*
    6585                 :       For now this record is only informative. It could serve when applying
    6586                 :       logs to a backup, but that needs more thought. Assume table became
    6587                 :       corrupted. It is repaired, then some writes happen to it.
    6588                 :       Later we restore an old backup, and want to apply this REDO_REPAIR_TABLE
    6589                 :       record. For it to give the same result as originally, the table should
    6590                 :       be corrupted the same way, so applying previous REDOs should produce the
    6591                 :       same corruption; that's really not guaranteed (different execution paths
    6592                 :       in execution of REDOs vs runtime code so not same bugs hit, temporary
    6593                 :       hardware issues not repeatable etc). Corruption may not be repeatable.
    6594                 :       A reasonable solution is to execute the REDO_REPAIR_TABLE record and
    6595                 :       check if the checksum of the resulting table matches what it was at the
    6596                 :       end of the original repair (should be stored in log record); or execute
    6597                 :       the REDO_REPAIR_TABLE if the checksum of the table-before-repair matches
    6598                 :       was it was at the start of the original repair (should be stored in log
    6599                 :       record).
    6600                 :     */
    6601                 :     LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
    6602                 :     uchar log_data[FILEID_STORE_SIZE + 8 + 8];
    6603                 :     LSN lsn;
    6604                 : 
    6605                 :     /*
    6606                 :       testflag gives an idea of what REPAIR did (in particular T_QUICK
    6607                 :       or not: did it touch the data file or not?).
    6608                 :     */
    6609               0 :     int8store(log_data + FILEID_STORE_SIZE, param->testflag);
    6610                 :     /* org_key_map is used when recreating index after a load data infile */
    6611               0 :     int8store(log_data + FILEID_STORE_SIZE + 8, param->org_key_map);
    6612                 : 
    6613               0 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    6614               0 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
    6615                 : 
    6616               0 :     share->now_transactional= 1;
    6617               0 :     if (unlikely(translog_write_record(&lsn, LOGREC_REDO_REPAIR_TABLE,
    6618                 :                                        &dummy_transaction_object, info,
    6619                 :                                        (translog_size_t) sizeof(log_data),
    6620                 :                                        sizeof(log_array)/sizeof(log_array[0]),
    6621                 :                                        log_array, log_data, NULL) ||
    6622                 :                  translog_flush(lsn)))
    6623               0 :       return TRUE;
    6624                 :     /*
    6625                 :       The table's existence was made durable earlier (MY_SYNC_DIR passed to
    6626                 :       maria_change_to_newfile()). All pages have been flushed, state too, we
    6627                 :       need to force it to disk. Old REDOs should not be applied to the table,
    6628                 :       which is already enforced as skip_redos_lsn was increased in
    6629                 :       protect_against_repair_crash(). But if this is an explicit repair,
    6630                 :       even UNDO phase should ignore this table: create_rename_lsn should be
    6631                 :       increased, and this also serves for the REDO_REPAIR to be ignored by
    6632                 :       maria_read_log.
    6633                 :       The fully correct order would be: sync data and index file, remove crash
    6634                 :       mark and update LSNs then write state and sync index file. But at this
    6635                 :       point state (without crash mark) is already written.
    6636                 :     */
    6637               0 :     if ((!(param->testflag & T_NO_CREATE_RENAME_LSN) &&
    6638                 :          _ma_update_state_lsns(share, lsn, share->state.create_trid, FALSE,
    6639                 :                                FALSE)) ||
    6640                 :         _ma_sync_table_files(info))
    6641               0 :       return TRUE;
    6642               0 :     share->now_transactional= save_now_transactional;
    6643                 :   }
    6644               0 :   return FALSE;
    6645                 : }
    6646                 : 
    6647                 : 
    6648                 : /**
    6649                 :   Writes an UNDO record which if executed in UNDO phase, will empty the
    6650                 :   table. Such record is thus logged only in certain cases of bulk insert
    6651                 :   (table needs to be empty etc).
    6652                 : */
    6653                 : my_bool write_log_record_for_bulk_insert(MARIA_HA *info)
    6654               0 : {
    6655                 :   LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
    6656                 :   uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE];
    6657                 :   LSN lsn;
    6658               0 :   lsn_store(log_data, info->trn->undo_lsn);
    6659               0 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    6660               0 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
    6661               0 :   return translog_write_record(&lsn, LOGREC_UNDO_BULK_INSERT,
    6662                 :                                info->trn, info,
    6663                 :                                (translog_size_t)
    6664                 :                                log_array[TRANSLOG_INTERNAL_PARTS +
    6665                 :                                          0].length,
    6666                 :                                TRANSLOG_INTERNAL_PARTS + 1, log_array,
    6667                 :                                log_data + LSN_STORE_SIZE, NULL) ||
    6668                 :     translog_flush(lsn); /* WAL */
    6669                 : }
    6670                 : 
    6671                 : 
    6672                 : /* Give error message why reading of key page failed */
    6673                 : 
    6674                 : static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
    6675                 :                                  my_off_t position)
    6676               0 : {
    6677                 :   char buff[11];
    6678               0 :   uint32 block_size= info->s->block_size;
    6679                 : 
    6680               0 :   if (my_errno == HA_ERR_CRASHED)
    6681               0 :     _ma_check_print_error(param,
    6682                 :                           "Wrong base information on indexpage at page: %s",
    6683                 :                           llstr(position / block_size, buff));
    6684                 :   else
    6685               0 :     _ma_check_print_error(param,
    6686                 :                           "Can't read indexpage from page: %s, "
    6687                 :                           "error: %d",
    6688                 :                           llstr(position / block_size, buff), my_errno);
    6689                 : }
    6690                 : 
    6691                 : 
    6692                 : /**
    6693                 :   When we want to check a table, we verify that the transaction ids of rows
    6694                 :   and keys are not bigger than the biggest id generated by Maria so far, which
    6695                 :   is returned by the function below.
    6696                 : 
    6697                 :   @note If control file is not open, 0 may be returned; to not confuse
    6698                 :   this with a valid max trid of 0, the caller should notice that it failed to
    6699                 :   open the control file (ma_control_file_inited() can serve for that).
    6700                 : */
    6701                 : 
    6702                 : static TrID max_trid_in_system(void)
    6703               0 : {
    6704               0 :   TrID id= trnman_get_max_trid(); /* 0 if transac manager not initialized */
    6705                 :   /* 'id' may be far bigger, if last shutdown is old */
    6706               0 :   return max(id, max_trid_in_control_file);
    6707                 : }
    6708                 : 
    6709                 : 
    6710                 : static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid)
    6711               0 : {
    6712                 :   char buff[22], buff2[22];
    6713               0 :   if (!param->not_visible_rows_found++)
    6714                 :   {
    6715               0 :     if (!ma_control_file_inited())
    6716                 :     {
    6717               0 :       _ma_check_print_warning(param,
    6718                 :                               "Found row with transaction id %s but no "
    6719                 :                               "maria_control_file was specified.  "
    6720                 :                               "The table may be corrupted",
    6721                 :                               llstr(used_trid, buff));
    6722                 :     }
    6723                 :     else
    6724                 :     {
    6725               0 :       _ma_check_print_error(param,
    6726                 :                             "Found row with transaction id %s when max "
    6727                 :                             "transaction id according to maria_control_file "
    6728                 :                             "is %s",
    6729                 :                             llstr(used_trid, buff),
    6730                 :                             llstr(param->max_trid, buff2));
    6731                 :     }
    6732                 :   }
    6733                 : }
    6734                 : 
    6735                 : 
    6736                 : /**
    6737                 :   Mark that we can retry normal repair if we used quick repair
    6738                 : 
    6739                 :   We shouldn't do this in case of disk error as in this case we are likely
    6740                 :   to loose much more than expected.
    6741                 : */
    6742                 : 
    6743                 : void retry_if_quick(MARIA_SORT_PARAM *sort_param, int error)
    6744               0 : {
    6745               0 :   HA_CHECK *param=sort_param->sort_info->param;
    6746                 : 
    6747               0 :   if (!sort_param->fix_datafile && error >= HA_ERR_FIRST)
    6748                 :   {
    6749               0 :     param->retry_repair=1;
    6750               0 :     param->testflag|=T_RETRY_WITHOUT_QUICK;
    6751                 :   }
    6752                 : }

Generated by: LTP GCOV extension version 1.4