2006-04-11 16:45:10 +03:00
/* Copyright (C) 2006-2003 MySQL AB
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-03-02 11:20:23 +01:00
the Free Software Foundation ; version 2 of the License .
2006-04-11 16:45:10 +03:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA */
/* Describe, check and repair of MARIA tables */
# include "ma_fulltext.h"
# include <myisamchk.h>
2006-08-11 01:16:51 +02:00
# include <my_bit.h>
2006-04-11 16:45:10 +03:00
# include <m_ctype.h>
# include <stdarg.h>
# include <my_getopt.h>
# ifdef HAVE_SYS_VADVICE_H
# include <sys/vadvise.h>
# endif
# ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
# endif
SET_STACK_SIZE ( 9000 ) /* Minimum stack size for program */
# ifndef USE_RAID
# define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
# define my_raid_delete(A,B,C) my_delete(A,B)
# endif
static uint decode_bits ;
static char * * default_argv ;
2007-01-18 21:38:14 +02:00
static const char * load_default_groups [ ] = { " maria_chk " , 0 } ;
2006-04-11 16:45:10 +03:00
static const char * set_collation_name , * opt_tmpdir ;
static CHARSET_INFO * set_collation ;
static const char * my_progname_short ;
static int stopwords_inited = 0 ;
2007-01-18 21:38:14 +02:00
static MY_TMPDIR maria_chk_tmpdir ;
2006-04-11 16:45:10 +03:00
static const char * type_names [ ] =
2007-01-18 21:38:14 +02:00
{
" impossible " , " char " , " binary " , " short " , " long " , " float " ,
2006-04-11 16:45:10 +03:00
" double " , " number " , " unsigned short " ,
" unsigned long " , " longlong " , " ulonglong " , " int24 " ,
2007-04-19 13:18:56 +03:00
" uint24 " , " int8 " , " varchar " , " varbin " , " varchar2 " , " varbin2 " , " bit " ,
" ? " , " ? "
2007-01-18 21:38:14 +02:00
} ;
2006-04-11 16:45:10 +03:00
static const char * prefix_packed_txt = " packed " ,
* bin_packed_txt = " prefix " ,
* diff_txt = " stripped " ,
* null_txt = " NULL " ,
* blob_txt = " BLOB " ;
static const char * field_pack [ ] =
2007-01-18 21:38:14 +02:00
{
" " , " no endspace " , " no prespace " ,
2006-04-11 16:45:10 +03:00
" no zeros " , " blob " , " constant " , " table-lockup " ,
2007-01-18 21:38:14 +02:00
" always zero " , " varchar " , " unique-hash " , " ? " , " ? "
} ;
static const char * record_formats [ ] =
{
" Fixed length " , " Packed " , " Compressed " , " Block " , " ? "
} ;
2006-04-11 16:45:10 +03:00
static const char * maria_stats_method_str = " nulls_unequal " ;
static void get_options ( int * argc , char * * * argv ) ;
static void print_version ( void ) ;
static void usage ( void ) ;
2007-01-18 21:38:14 +02:00
static int maria_chk ( HA_CHECK * param , char * filename ) ;
2007-07-02 20:45:15 +03:00
static void descript ( HA_CHECK * param , register MARIA_HA * info , char * name ) ;
2006-04-11 16:45:10 +03:00
static int maria_sort_records ( HA_CHECK * param , register MARIA_HA * info ,
2007-07-02 20:45:15 +03:00
char * name , uint sort_key ,
2007-01-18 21:38:14 +02:00
my_bool write_info , my_bool update_index ) ;
2006-04-11 16:45:10 +03:00
static int sort_record_index ( MARIA_SORT_PARAM * sort_param , MARIA_HA * info ,
MARIA_KEYDEF * keyinfo ,
2007-07-02 20:45:15 +03:00
my_off_t page , uchar * buff , uint sortkey ,
2006-04-11 16:45:10 +03:00
File new_file , my_bool update_index ) ;
HA_CHECK check_param ;
/* Main program */
int main ( int argc , char * * argv )
{
int error ;
MY_INIT ( argv [ 0 ] ) ;
my_progname_short = my_progname + dirname_length ( my_progname ) ;
2007-01-18 21:38:14 +02:00
maria_chk_init ( & check_param ) ;
2006-04-11 16:45:10 +03:00
check_param . opt_lock_memory = 1 ; /* Lock memory if possible */
check_param . using_global_keycache = 0 ;
get_options ( & argc , ( char * * * ) & argv ) ;
maria_quick_table_bits = decode_bits ;
error = 0 ;
maria_init ( ) ;
while ( - - argc > = 0 )
{
2007-01-18 21:38:14 +02:00
int new_error = maria_chk ( & check_param , * ( argv + + ) ) ;
2006-04-11 16:45:10 +03:00
if ( ( check_param . testflag & T_REP_ANY ) ! = T_REP )
check_param . testflag & = ~ T_REP ;
VOID ( fflush ( stdout ) ) ;
VOID ( fflush ( stderr ) ) ;
if ( ( check_param . error_printed | check_param . warning_printed ) & &
( check_param . testflag & T_FORCE_CREATE ) & &
( ! ( check_param . testflag & ( T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
T_SORT_INDEX ) ) ) )
{
2007-08-29 09:03:10 +03:00
ulonglong old_testflag = check_param . testflag ;
2006-04-11 16:45:10 +03:00
if ( ! ( check_param . testflag & T_REP ) )
check_param . testflag | = T_REP_BY_SORT ;
check_param . testflag & = ~ T_EXTEND ; /* Don't needed */
2007-01-18 21:38:14 +02:00
error | = maria_chk ( & check_param , argv [ - 1 ] ) ;
2006-04-11 16:45:10 +03:00
check_param . testflag = old_testflag ;
VOID ( fflush ( stdout ) ) ;
VOID ( fflush ( stderr ) ) ;
}
else
error | = new_error ;
2007-08-29 09:03:10 +03:00
if ( argc & & ( ! ( check_param . testflag & T_SILENT ) | |
check_param . testflag & T_INFO ) )
2006-04-11 16:45:10 +03:00
{
puts ( " \n --------- \n " ) ;
VOID ( fflush ( stdout ) ) ;
}
}
if ( check_param . total_files > 1 )
{ /* Only if descript */
char buff [ 22 ] , buff2 [ 22 ] ;
if ( ! ( check_param . testflag & T_SILENT ) | | check_param . testflag & T_INFO )
puts ( " \n --------- \n " ) ;
printf ( " \n Total of all %d MARIA-files: \n Data records: %9s Deleted blocks: %9s \n " , check_param . total_files , llstr ( check_param . total_records , buff ) ,
llstr ( check_param . total_deleted , buff2 ) ) ;
}
free_defaults ( default_argv ) ;
2007-01-18 21:38:14 +02:00
free_tmpdir ( & maria_chk_tmpdir ) ;
2006-04-11 16:45:10 +03:00
maria_end ( ) ;
my_end ( check_param . testflag & T_INFO ?
MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR ) ;
exit ( error ) ;
# ifndef _lint
return 0 ; /* No compiler warning */
# endif
} /* main */
enum options_mc {
OPT_CHARSETS_DIR = 256 , OPT_SET_COLLATION , OPT_START_CHECK_POS ,
2007-09-27 14:18:28 +03:00
OPT_CORRECT_CHECKSUM , OPT_PAGE_BUFFER_SIZE ,
2006-04-11 16:45:10 +03:00
OPT_KEY_CACHE_BLOCK_SIZE , OPT_MARIA_BLOCK_SIZE ,
OPT_READ_BUFFER_SIZE , OPT_WRITE_BUFFER_SIZE , OPT_SORT_BUFFER_SIZE ,
OPT_SORT_KEY_BLOCKS , OPT_DECODE_BITS , OPT_FT_MIN_WORD_LEN ,
OPT_FT_MAX_WORD_LEN , OPT_FT_STOPWORD_FILE ,
OPT_MAX_RECORD_LENGTH , OPT_AUTO_CLOSE , OPT_STATS_METHOD
} ;
static struct my_option my_long_options [ ] =
{
{ " analyze " , ' a ' ,
" Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# ifdef __NETWARE__
{ " autoclose " , OPT_AUTO_CLOSE , " Auto close the screen on exit for Netware. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# endif
{ " block-search " , ' b ' ,
" No help available. " ,
0 , 0 , 0 , GET_ULONG , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " backup " , ' B ' ,
" Make a backup of the .MYD file as 'filename-time.BAK'. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " character-sets-dir " , OPT_CHARSETS_DIR ,
" Directory where character sets are. " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & charsets_dir , 0 , 0 , GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2006-04-11 16:45:10 +03:00
{ " check " , ' c ' ,
" Check table for errors. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " check-only-changed " , ' C ' ,
" Check only tables that have changed since last check. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed). " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " correct-checksum " , OPT_CORRECT_CHECKSUM ,
" Correct checksum information for table. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# ifndef DBUG_OFF
{ " debug " , ' # ' ,
" Output debug log. Often this is 'd:t:o,filename'. " ,
0 , 0 , 0 , GET_STR , OPT_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# endif
{ " description " , ' d ' ,
" Prints some information about table. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " data-file-length " , ' D ' ,
" Max length of data file (when recreating data-file when it's full). " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . max_data_file_length ,
( uchar * * ) & check_param . max_data_file_length ,
2006-04-11 16:45:10 +03:00
0 , GET_LL , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " extend-check " , ' e ' ,
" If used when checking a table, ensure that the table is 100 percent consistent, which will take a long time. If used when repairing a table, try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option with repair if you are not totally desperate. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " fast " , ' F ' ,
" Check only tables that haven't been closed properly. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed). " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " force " , ' f ' ,
" Restart with -r if there are any errors in the table. States will be updated as with --update-state. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " HELP " , ' H ' ,
" Display this help and exit. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " help " , ' ? ' ,
" Display this help and exit. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " information " , ' i ' ,
" Print statistics information about table that is checked. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " keys-used " , ' k ' ,
" Tell MARIA to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts. " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . keys_in_use ,
( uchar * * ) & check_param . keys_in_use ,
2006-04-11 16:45:10 +03:00
0 , GET_ULL , REQUIRED_ARG , - 1 , 0 , 0 , 0 , 0 , 0 } ,
{ " max-record-length " , OPT_MAX_RECORD_LENGTH ,
2007-01-18 21:38:14 +02:00
" Skip rows bigger than this if maria_chk can't allocate memory to hold it " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . max_record_length ,
( uchar * * ) & check_param . max_record_length ,
2006-04-11 16:45:10 +03:00
0 , GET_ULL , REQUIRED_ARG , LONGLONG_MAX , 0 , LONGLONG_MAX , 0 , 0 , 0 } ,
{ " medium-check " , ' m ' ,
" Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " quick " , ' q ' , " Faster repair by not modifying the data file. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " read-only " , ' T ' ,
" Don't mark table as checked. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " recover " , ' r ' ,
" Can fix almost anything except unique keys that aren't unique. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " parallel-recover " , ' p ' ,
" Same as '-r' but creates all the keys in parallel. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " safe-recover " , ' o ' ,
" Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " sort-recover " , ' n ' ,
" Force recovering with sorting even if the temporary file was very big. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# ifdef DEBUG
{ " start-check-pos " , OPT_START_CHECK_POS ,
" No help available. " ,
0 , 0 , 0 , GET_ULL , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# endif
{ " set-auto-increment " , ' A ' ,
" Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1. " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . auto_increment_value ,
( uchar * * ) & check_param . auto_increment_value ,
2006-04-11 16:45:10 +03:00
0 , GET_ULL , OPT_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " set-collation " , OPT_SET_COLLATION ,
" Change the collation used by the index " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & set_collation_name , 0 , 0 , GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2006-04-11 16:45:10 +03:00
{ " set-variable " , ' O ' ,
" Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value. " ,
0 , 0 , 0 , GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " silent " , ' s ' ,
2007-01-18 21:38:14 +02:00
" Only print errors. One can use two -s to make maria_chk very silent. " ,
2006-04-11 16:45:10 +03:00
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " sort-index " , ' S ' ,
" Sort index blocks. This speeds up 'read-next' in applications. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " sort-records " , ' R ' ,
" Sort records according to an index. This makes your data much more localized and may speed up things. (It may be VERY slow to do a sort the first time!) " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . opt_sort_key ,
( uchar * * ) & check_param . opt_sort_key ,
2006-04-11 16:45:10 +03:00
0 , GET_UINT , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " tmpdir " , ' t ' ,
" Path for temporary files. " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & opt_tmpdir ,
2006-04-11 16:45:10 +03:00
0 , 0 , GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " update-state " , ' U ' ,
" Mark tables as crashed if any errors were found. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " unpack " , ' u ' ,
" Unpack file packed with mariapack. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " verbose " , ' v ' ,
" Print more information. This can be used with --description and --check. Use many -v for more verbosity! " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " version " , ' V ' ,
" Print version and exit. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " wait " , ' w ' ,
" Wait if table is locked. " ,
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2007-09-27 14:18:28 +03:00
{ " page_buffer_size " , OPT_PAGE_BUFFER_SIZE , " " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . use_buffers , ( uchar * * ) & check_param . use_buffers , 0 ,
2006-04-11 16:45:10 +03:00
GET_ULONG , REQUIRED_ARG , ( long ) USE_BUFFER_INIT , ( long ) MALLOC_OVERHEAD ,
( long ) ~ 0L , ( long ) MALLOC_OVERHEAD , ( long ) IO_SIZE , 0 } ,
{ " read_buffer_size " , OPT_READ_BUFFER_SIZE , " " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . read_buffer_length ,
( uchar * * ) & check_param . read_buffer_length , 0 , GET_ULONG , REQUIRED_ARG ,
2006-04-11 16:45:10 +03:00
( long ) READ_BUFFER_INIT , ( long ) MALLOC_OVERHEAD ,
( long ) ~ 0L , ( long ) MALLOC_OVERHEAD , ( long ) 1L , 0 } ,
{ " write_buffer_size " , OPT_WRITE_BUFFER_SIZE , " " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . write_buffer_length ,
( uchar * * ) & check_param . write_buffer_length , 0 , GET_ULONG , REQUIRED_ARG ,
2006-04-11 16:45:10 +03:00
( long ) READ_BUFFER_INIT , ( long ) MALLOC_OVERHEAD ,
( long ) ~ 0L , ( long ) MALLOC_OVERHEAD , ( long ) 1L , 0 } ,
{ " sort_buffer_size " , OPT_SORT_BUFFER_SIZE , " " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . sort_buffer_length ,
( uchar * * ) & check_param . sort_buffer_length , 0 , GET_ULONG , REQUIRED_ARG ,
2006-04-11 16:45:10 +03:00
( long ) SORT_BUFFER_INIT , ( long ) ( MIN_SORT_BUFFER + MALLOC_OVERHEAD ) ,
( long ) ~ 0L , ( long ) MALLOC_OVERHEAD , ( long ) 1L , 0 } ,
{ " sort_key_blocks " , OPT_SORT_KEY_BLOCKS , " " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & check_param . sort_key_blocks ,
( uchar * * ) & check_param . sort_key_blocks , 0 , GET_ULONG , REQUIRED_ARG ,
2006-04-11 16:45:10 +03:00
BUFFERS_WHEN_SORTING , 4L , 100L , 0L , 1L , 0 } ,
2007-07-02 20:45:15 +03:00
{ " decode_bits " , OPT_DECODE_BITS , " " , ( uchar * * ) & decode_bits ,
( uchar * * ) & decode_bits , 0 , GET_UINT , REQUIRED_ARG , 9L , 4L , 17L , 0L , 1L , 0 } ,
{ " ft_min_word_len " , OPT_FT_MIN_WORD_LEN , " " , ( uchar * * ) & ft_min_word_len ,
( uchar * * ) & ft_min_word_len , 0 , GET_ULONG , REQUIRED_ARG , 4 , 1 , HA_FT_MAXCHARLEN ,
2006-04-11 16:45:10 +03:00
0 , 1 , 0 } ,
2007-07-02 20:45:15 +03:00
{ " ft_max_word_len " , OPT_FT_MAX_WORD_LEN , " " , ( uchar * * ) & ft_max_word_len ,
( uchar * * ) & ft_max_word_len , 0 , GET_ULONG , REQUIRED_ARG , HA_FT_MAXCHARLEN , 10 ,
2006-04-11 16:45:10 +03:00
HA_FT_MAXCHARLEN , 0 , 1 , 0 } ,
{ " maria_ft_stopword_file " , OPT_FT_STOPWORD_FILE ,
" Use stopwords from this file instead of built-in list. " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & ft_stopword_file , ( uchar * * ) & ft_stopword_file , 0 , GET_STR ,
2006-04-11 16:45:10 +03:00
REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ " stats_method " , OPT_STATS_METHOD ,
2007-10-04 20:33:42 +03:00
" Specifies how index statistics collection code should treat NULLs. "
2006-04-11 16:45:10 +03:00
" Possible values of name are \" nulls_unequal \" (default behavior for 4.1/5.0), "
" \" nulls_equal \" (emulate 4.0 behavior), and \" nulls_ignored \" . " ,
2007-07-02 20:45:15 +03:00
( uchar * * ) & maria_stats_method_str , ( uchar * * ) & maria_stats_method_str , 0 ,
2006-04-11 16:45:10 +03:00
GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
# include <help_start.h>
static void print_version ( void )
{
2007-01-18 21:38:14 +02:00
printf ( " %s Ver 1.0 for %s at %s \n " , my_progname , SYSTEM_TYPE ,
2006-04-11 16:45:10 +03:00
MACHINE_TYPE ) ;
NETWARE_SET_SCREEN_MODE ( 1 ) ;
}
static void usage ( void )
{
print_version ( ) ;
puts ( " By Monty, for your professional use " ) ;
puts ( " This software comes with NO WARRANTY: see the PUBLIC for details. \n " ) ;
puts ( " Description, check and repair of MARIA tables. " ) ;
puts ( " Used without options all tables on the command will be checked for errors " ) ;
printf ( " Usage: %s [OPTIONS] tables[.MYI] \n " , my_progname_short ) ;
printf ( " \n Global options: \n " ) ;
# ifndef DBUG_OFF
printf ( " \
- # , - - debug = . . . Output debug log . Often this is ' d : t : o , filename ' . \ n " );
# endif
printf ( " \
- ? , - - help Display this help and exit . \ n \
- O , - - set - variable var = option . \ n \
Change the value of a variable . Please note that \ n \
this option is deprecated ; you can set variables \ n \
directly with ' - - variable - name = value ' . \ n \
- t , - - tmpdir = path Path for temporary files . Multiple paths can be \ n \
specified , separated by " );
Completion of merge of mysql-5.1 into mysql-maria.
Manually imported changes done to MyISAM (include/myisam.h,
storage/myisam/*, sql/ha_myisam.*, mysql-test/t/myisam.test,
mysql-test/t/ps_2myisam.test) the last
months into Maria (tedious, should do it more frequently in the
future), including those not done at the previous 5.1->Maria merge
(please in the future don't forget to apply MyISAM changes to Maria
when you merge 5.1 into Maria).
Note: I didn't try to import anything which could be MyISAM-related
in other tests of mysql-test (I didn't want to dig in all csets),
but as QA is working to make most tests re-usable for other engines
(Falcon), it is likely that we'll benefit from this and just have
to set engine=Maria somewhere to run those tests on Maria.
func_group and partition tests fail but they already do in main 5.1
on my machine. No Valgrind error in t/*maria*.test.
Monty: please see the commit comment of maria.result and check.
BitKeeper/deleted/.del-ha_maria.m4:
Delete: config/ac-macros/ha_maria.m4
configure.in:
fix for the new way of enabling engines
include/maria.h:
importing changes done to MyISAM the last months into Maria
include/my_handler.h:
importing changes done to MyISAM the last months into Maria
include/myisam.h:
importing changes done to MyISAM the last months into Maria
mysql-test/r/maria.result:
identical to myisam.result, except the engine name in some places
AND in the line testing key_block_size=1000000000000000000:
Maria gives a key block size of 8192 while MyISAM gives 4096;
is it explainable by the difference between MARIA_KEY_BLOCK_LENGTH
and the same constant in MyISAM? Monty?
mysql-test/r/ps_maria.result:
identical to ps_2myisam.result (except the engine name in some places)
mysql-test/t/maria.test:
instead of engine=maria everywhere, I use @@storage_engine (reduces
the diff with myisam.test).
importing changes done to MyISAM the last months into Maria
mysys/my_handler.c:
importing changes done to MyISAM the last months into Maria
sql/ha_maria.cc:
importing changes done to MyISAM the last months into Maria
sql/ha_maria.h:
importing changes done to MyISAM the last months into Maria
sql/mysqld.cc:
unneeded
storage/maria/Makefile.am:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_check.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_create.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_delete_table.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_dynrec.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_extra.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ft_boolean_search.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ft_eval.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ft_nlq_search.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ft_parser.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ft_test1.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ft_update.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_ftdefs.h:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_key.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_open.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_page.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_rkey.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_rsamepos.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_rt_index.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_rt_mbr.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_search.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_sort.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_test1.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_test2.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_test3.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_update.c:
importing changes done to MyISAM the last months into Maria
storage/maria/ma_write.c:
importing changes done to MyISAM the last months into Maria
storage/maria/maria_chk.c:
importing changes done to MyISAM the last months into Maria
storage/maria/maria_def.h:
importing changes done to MyISAM the last months into Maria
storage/maria/maria_ftdump.c:
importing changes done to MyISAM the last months into Maria
storage/maria/maria_pack.c:
importing changes done to MyISAM the last months into Maria
2006-08-10 16:36:54 +02:00
# if defined( __WIN__) || defined(__NETWARE__)
2006-04-11 16:45:10 +03:00
printf ( " semicolon (;) " ) ;
# else
printf ( " colon (:) " ) ;
# endif
printf ( " , they will be used \n \
in a round - robin fashion . \ n \
- s , - - silent Only print errors . One can use two - s to make \ n \
2007-01-18 21:38:14 +02:00
maria_chk very silent . \ n \
2006-04-11 16:45:10 +03:00
- v , - - verbose Print more information . This can be used with \ n \
- - description and - - check . Use many - v for more verbosity . \ n \
- V , - - version Print version and exit . \ n \
- w , - - wait Wait if table is locked . \ n \ n " );
# ifdef DEBUG
puts ( " --start-check-pos=# Start reading file at given offset. \n " ) ;
# endif
2007-01-18 21:38:14 +02:00
puts ( " Check options (check is the default action for maria_chk): \n \
2006-04-11 16:45:10 +03:00
- c , - - check Check table for errors . \ n \
- e , - - extend - check Check the table VERY throughly . Only use this in \ n \
2007-01-18 21:38:14 +02:00
extreme cases as maria_chk should normally be able to \ n \
2006-04-11 16:45:10 +03:00
find out if the table is ok even without this switch . \ n \
- F , - - fast Check only tables that haven ' t been closed properly . \ n \
- C , - - check - only - changed \ n \
Check only tables that have changed since last check . \ n \
- f , - - force Restart with ' - r ' if there are any errors in the table . \ n \
States will be updated as with ' - - update - state ' . \ n \
- i , - - information Print statistics information about table that is checked . \ n \
- m , - - medium - check Faster than extend - check , but only finds 99.99 % of \ n \
all errors . Should be good enough for most cases . \ n \
- U - - update - state Mark tables as crashed if you find any errors . \ n \
- T , - - read - only Don ' t mark table as checked . \ n " );
puts ( " Repair options (When using '-r' or '-o'): \n \
- B , - - backup Make a backup of the . MYD file as ' filename - time . BAK ' . \ n \
- - correct - checksum Correct checksum information for table . \ n \
- D , - - data - file - length = # Max length of data file ( when recreating data \ n \
file when it ' s full ) . \ n \
- e , - - extend - check Try to recover every possible row from the data file \ n \
Normally this will also find a lot of garbage rows ; \ n \
Don ' t use this option if you are not totally desperate . \ n \
- f , - - force Overwrite old temporary files . \ n \
- k , - - keys - used = # Tell MARIA to update only some specific keys . # is a \ n \
bit mask of which keys to use . This can be used to \ n \
get faster inserts . \ n \
- - max - record - length = # \ n \
2007-01-18 21:38:14 +02:00
Skip rows bigger than this if maria_chk can ' t allocate \ n \
2006-04-11 16:45:10 +03:00
memory to hold it . \ n \
- r , - - recover Can fix almost anything except unique keys that aren ' t \ n \
unique . \ n \
- n , - - sort - recover Forces recovering with sorting even if the temporary \ n \
file would be very big . \ n \
- p , - - parallel - recover \ n \
Uses the same technique as ' - r ' and ' - n ' , but creates \ n \
all the keys in parallel , in different threads . \ n \
- o , - - safe - recover Uses old recovery method ; Slower than ' - r ' but can \ n \
handle a couple of cases where ' - r ' reports that it \ n \
can ' t fix the data file . \ n \
- - character - sets - dir = . . . \ n \
Directory where character sets are . \ n \
- - set - collation = name \ n \
Change the collation used by the index . \ n \
- q , - - quick Faster repair by not modifying the data file . \ n \
2007-01-18 21:38:14 +02:00
One can give a second ' - q ' to force maria_chk to \ n \
2006-04-11 16:45:10 +03:00
modify the original datafile in case of duplicate keys . \ n \
NOTE : Tables where the data file is currupted can ' t be \ n \
fixed with this option . \ n \
- u , - - unpack Unpack file packed with mariapack . \ n \
" );
puts ( " Other actions: \n \
- a , - - analyze Analyze distribution of keys . Will make some joins in \ n \
MySQL faster . You can check the calculated distribution \ n \
by using ' - - description - - verbose table_name ' . \ n \
- - stats_method = name Specifies how index statistics collection code should \ n \
2007-10-04 20:33:42 +03:00
treat NULLs . Possible values of name are \ " nulls_unequal \" \n \
2006-04-11 16:45:10 +03:00
( default for 4.1 / 5.0 ) , \ " nulls_equal \" (emulate 4.0), and \n \
\ " nulls_ignored \" . \n \
- d , - - description Prints some information about table . \ n \
- A , - - set - auto - increment [ = value ] \ n \
Force auto_increment to start at this or higher value \ n \
If no value is given , then sets the next auto_increment \ n \
value to the highest used value for the auto key + 1. \ n \
- S , - - sort - index Sort index blocks . This speeds up ' read - next ' in \ n \
applications . \ n \
- R , - - sort - records = # \ n \
Sort records according to an index . This makes your \ n \
data much more localized and may speed up things \ n \
( It may be VERY slow to do a sort the first time ! ) . \ n \
- b , - - block - search = # \ n \
Find a record , a block at given offset belongs to . " );
print_defaults ( " my " , load_default_groups ) ;
my_print_variables ( my_long_options ) ;
}
# include <help_end.h>
const char * maria_stats_method_names [ ] = { " nulls_unequal " , " nulls_equal " ,
" nulls_ignored " , NullS } ;
TYPELIB maria_stats_method_typelib = {
array_elements ( maria_stats_method_names ) - 1 , " " ,
maria_stats_method_names , NULL } ;
/* Read options */
static my_bool
get_one_option ( int optid ,
const struct my_option * opt __attribute__ ( ( unused ) ) ,
char * argument )
{
switch ( optid ) {
# ifdef __NETWARE__
case OPT_AUTO_CLOSE :
setscreenmode ( SCR_AUTOCLOSE_ON_EXIT ) ;
break ;
# endif
case ' a ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_STATISTICS ;
else
check_param . testflag | = T_STATISTICS ;
break ;
case ' A ' :
if ( argument )
check_param . auto_increment_value = strtoull ( argument , NULL , 0 ) ;
else
check_param . auto_increment_value = 0 ; /* Set to max used value */
check_param . testflag | = T_AUTO_INC ;
break ;
case ' b ' :
check_param . search_after_block = strtoul ( argument , NULL , 10 ) ;
break ;
case ' B ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_BACKUP_DATA ;
else
check_param . testflag | = T_BACKUP_DATA ;
break ;
case ' c ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_CHECK ;
else
check_param . testflag | = T_CHECK ;
break ;
case ' C ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ ( T_CHECK | T_CHECK_ONLY_CHANGED ) ;
else
check_param . testflag | = T_CHECK | T_CHECK_ONLY_CHANGED ;
break ;
case ' D ' :
check_param . max_data_file_length = strtoll ( argument , NULL , 10 ) ;
break ;
case ' s ' : /* silent */
if ( argument = = disabled_my_option )
check_param . testflag & = ~ ( T_SILENT | T_VERY_SILENT ) ;
else
{
if ( check_param . testflag & T_SILENT )
check_param . testflag | = T_VERY_SILENT ;
check_param . testflag | = T_SILENT ;
check_param . testflag & = ~ T_WRITE_LOOP ;
}
break ;
case ' w ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_WAIT_FOREVER ;
else
check_param . testflag | = T_WAIT_FOREVER ;
break ;
case ' d ' : /* description if isam-file */
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_DESCRIPT ;
else
check_param . testflag | = T_DESCRIPT ;
break ;
case ' e ' : /* extend check */
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_EXTEND ;
else
check_param . testflag | = T_EXTEND ;
break ;
case ' i ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_INFO ;
else
check_param . testflag | = T_INFO ;
break ;
case ' f ' :
if ( argument = = disabled_my_option )
{
check_param . tmpfile_createflag = O_RDWR | O_TRUNC | O_EXCL ;
check_param . testflag & = ~ ( T_FORCE_CREATE | T_UPDATE_STATE ) ;
}
else
{
check_param . tmpfile_createflag = O_RDWR | O_TRUNC ;
check_param . testflag | = T_FORCE_CREATE | T_UPDATE_STATE ;
}
break ;
case ' F ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_FAST ;
else
check_param . testflag | = T_FAST ;
break ;
case ' k ' :
check_param . keys_in_use = ( ulonglong ) strtoll ( argument , NULL , 10 ) ;
break ;
case ' m ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_MEDIUM ;
else
check_param . testflag | = T_MEDIUM ; /* Medium check */
break ;
case ' r ' : /* Repair table */
check_param . testflag & = ~ T_REP_ANY ;
if ( argument ! = disabled_my_option )
check_param . testflag | = T_REP_BY_SORT ;
break ;
case ' p ' :
check_param . testflag & = ~ T_REP_ANY ;
if ( argument ! = disabled_my_option )
check_param . testflag | = T_REP_PARALLEL ;
break ;
case ' o ' :
check_param . testflag & = ~ T_REP_ANY ;
check_param . force_sort = 0 ;
if ( argument ! = disabled_my_option )
{
check_param . testflag | = T_REP ;
my_disable_async_io = 1 ; /* More safety */
}
break ;
case ' n ' :
check_param . testflag & = ~ T_REP_ANY ;
if ( argument = = disabled_my_option )
check_param . force_sort = 0 ;
else
{
check_param . testflag | = T_REP_BY_SORT ;
check_param . force_sort = 1 ;
}
break ;
case ' q ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ ( T_QUICK | T_FORCE_UNIQUENESS ) ;
else
check_param . testflag | =
( check_param . testflag & T_QUICK ) ? T_FORCE_UNIQUENESS : T_QUICK ;
break ;
case ' u ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ ( T_UNPACK | T_REP_BY_SORT ) ;
else
check_param . testflag | = T_UNPACK | T_REP_BY_SORT ;
break ;
case ' v ' : /* Verbose */
if ( argument = = disabled_my_option )
{
check_param . testflag & = ~ T_VERBOSE ;
check_param . verbose = 0 ;
}
else
{
check_param . testflag | = T_VERBOSE ;
check_param . verbose + + ;
}
break ;
case ' R ' : /* Sort records */
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_SORT_RECORDS ;
else
{
check_param . testflag | = T_SORT_RECORDS ;
check_param . opt_sort_key = ( uint ) atoi ( argument ) - 1 ;
if ( check_param . opt_sort_key > = MARIA_MAX_KEY )
{
fprintf ( stderr ,
" The value of the sort key is bigger than max key: %d. \n " ,
MARIA_MAX_KEY ) ;
exit ( 1 ) ;
}
}
break ;
case ' S ' : /* Sort index */
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_SORT_INDEX ;
else
check_param . testflag | = T_SORT_INDEX ;
break ;
case ' T ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_READONLY ;
else
check_param . testflag | = T_READONLY ;
break ;
case ' U ' :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_UPDATE_STATE ;
else
check_param . testflag | = T_UPDATE_STATE ;
break ;
case ' # ' :
2007-07-01 16:20:57 +03:00
DBUG_SET_INITIAL ( argument ? argument : " d:t:o,/tmp/maria_chk.trace " ) ;
2006-04-11 16:45:10 +03:00
break ;
case ' V ' :
print_version ( ) ;
exit ( 0 ) ;
case OPT_CORRECT_CHECKSUM :
if ( argument = = disabled_my_option )
check_param . testflag & = ~ T_CALC_CHECKSUM ;
else
check_param . testflag | = T_CALC_CHECKSUM ;
break ;
case OPT_STATS_METHOD :
{
int method ;
enum_handler_stats_method method_conv ;
2006-12-20 18:58:35 +01:00
LINT_INIT ( method_conv ) ;
2006-04-11 16:45:10 +03:00
maria_stats_method_str = argument ;
if ( ( method = find_type ( argument , & maria_stats_method_typelib , 2 ) ) < = 0 )
{
fprintf ( stderr , " Invalid value of stats_method: %s. \n " , argument ) ;
exit ( 1 ) ;
}
switch ( method - 1 ) {
case 0 :
method_conv = MI_STATS_METHOD_NULLS_EQUAL ;
break ;
case 1 :
method_conv = MI_STATS_METHOD_NULLS_NOT_EQUAL ;
break ;
case 2 :
method_conv = MI_STATS_METHOD_IGNORE_NULLS ;
break ;
2007-03-01 18:23:58 +01:00
default : assert ( 0 ) ; /* Impossible */
2006-04-11 16:45:10 +03:00
}
check_param . stats_method = method_conv ;
break ;
}
# ifdef DEBUG /* Only useful if debugging */
case OPT_START_CHECK_POS :
check_param . start_check_pos = strtoull ( argument , NULL , 0 ) ;
break ;
# endif
case ' H ' :
my_print_help ( my_long_options ) ;
exit ( 0 ) ;
case ' ? ' :
usage ( ) ;
exit ( 0 ) ;
}
return 0 ;
}
static void get_options ( register int * argc , register char * * * argv )
{
int ho_error ;
load_defaults ( " my " , load_default_groups , argc , argv ) ;
default_argv = * argv ;
if ( isatty ( fileno ( stdout ) ) )
check_param . testflag | = T_WRITE_LOOP ;
if ( ( ho_error = handle_options ( argc , argv , my_long_options , get_one_option ) ) )
exit ( ho_error ) ;
/* If using repair, then update checksum if one uses --update-state */
if ( ( check_param . testflag & T_UPDATE_STATE ) & &
( check_param . testflag & T_REP_ANY ) )
check_param . testflag | = T_CALC_CHECKSUM ;
if ( * argc = = 0 )
{
usage ( ) ;
exit ( - 1 ) ;
}
if ( ( check_param . testflag & T_UNPACK ) & &
( check_param . testflag & ( T_QUICK | T_SORT_RECORDS ) ) )
{
VOID ( fprintf ( stderr ,
" %s: --unpack can't be used with --quick or --sort-records \n " ,
my_progname_short ) ) ;
exit ( 1 ) ;
}
if ( ( check_param . testflag & T_READONLY ) & &
( check_param . testflag &
( T_REP_ANY | T_STATISTICS | T_AUTO_INC |
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE ) ) )
{
VOID ( fprintf ( stderr ,
" %s: Can't use --readonly when repairing or sorting \n " ,
my_progname_short ) ) ;
exit ( 1 ) ;
}
2007-01-18 21:38:14 +02:00
if ( init_tmpdir ( & maria_chk_tmpdir , opt_tmpdir ) )
2006-04-11 16:45:10 +03:00
exit ( 1 ) ;
2007-01-18 21:38:14 +02:00
check_param . tmpdir = & maria_chk_tmpdir ;
2006-04-11 16:45:10 +03:00
if ( set_collation_name )
if ( ! ( set_collation = get_charset_by_name ( set_collation_name ,
MYF ( MY_WME ) ) ) )
exit ( 1 ) ;
return ;
} /* get options */
/* Check table */
2007-07-02 20:45:15 +03:00
static int maria_chk ( HA_CHECK * param , char * filename )
2006-04-11 16:45:10 +03:00
{
int error , lock_type , recreate ;
int rep_quick = param - > testflag & ( T_QUICK | T_FORCE_UNIQUENESS ) ;
MARIA_HA * info ;
File datafile ;
char llbuff [ 22 ] , llbuff2 [ 22 ] ;
my_bool state_updated = 0 ;
MARIA_SHARE * share ;
2007-01-18 21:38:14 +02:00
DBUG_ENTER ( " maria_chk " ) ;
2006-04-11 16:45:10 +03:00
param - > out_flag = error = param - > warning_printed = param - > error_printed =
recreate = 0 ;
datafile = 0 ;
param - > isam_file_name = filename ; /* For error messages */
if ( ! ( info = maria_open ( filename ,
( param - > testflag & ( T_DESCRIPT | T_READONLY ) ) ?
O_RDONLY : O_RDWR ,
HA_OPEN_FOR_REPAIR |
( ( param - > testflag & T_WAIT_FOREVER ) ?
HA_OPEN_WAIT_IF_LOCKED :
( param - > testflag & T_DESCRIPT ) ?
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED ) ) ) )
{
/* Avoid twice printing of isam file name */
param - > error_printed = 1 ;
switch ( my_errno ) {
case HA_ERR_CRASHED :
_ma_check_print_error ( param , " '%s' doesn't have a correct index definition. You need to recreate it before you can do a repair " , filename ) ;
break ;
case HA_ERR_NOT_A_TABLE :
_ma_check_print_error ( param , " '%s' is not a MARIA-table " , filename ) ;
break ;
case HA_ERR_CRASHED_ON_USAGE :
_ma_check_print_error ( param , " '%s' is marked as crashed " , filename ) ;
break ;
case HA_ERR_CRASHED_ON_REPAIR :
_ma_check_print_error ( param , " '%s' is marked as crashed after last repair " , filename ) ;
break ;
case HA_ERR_OLD_FILE :
_ma_check_print_error ( param , " '%s' is a old type of MARIA-table " , filename ) ;
break ;
case HA_ERR_END_OF_FILE :
_ma_check_print_error ( param , " Couldn't read complete header from '%s' " , filename ) ;
break ;
case EAGAIN :
_ma_check_print_error ( param , " '%s' is locked. Use -w to wait until unlocked " , filename ) ;
break ;
case ENOENT :
_ma_check_print_error ( param , " File '%s' doesn't exist " , filename ) ;
break ;
case EACCES :
2007-01-18 21:38:14 +02:00
_ma_check_print_error ( param , " You don't have permission to use '%s' " ,
filename ) ;
2006-04-11 16:45:10 +03:00
break ;
default :
_ma_check_print_error ( param , " %d when opening MARIA-table '%s' " ,
my_errno , filename ) ;
break ;
}
DBUG_RETURN ( 1 ) ;
}
share = info - > s ;
share - > options & = ~ HA_OPTION_READ_ONLY_DATA ; /* We are modifing it */
share - > tot_locks - = share - > r_locks ;
share - > r_locks = 0 ;
2007-04-19 18:48:36 +03:00
maria_block_size = share - > base . block_size ;
2007-01-18 21:38:14 +02:00
2007-07-01 16:20:57 +03:00
if ( share - > data_file_type = = BLOCK_RECORD | |
( ( param - > testflag & T_UNPACK ) & &
share - > state . header . org_data_file_type = = BLOCK_RECORD ) )
2007-01-18 21:38:14 +02:00
{
2007-07-01 16:20:57 +03:00
if ( param - > testflag & T_SORT_RECORDS )
{
_ma_check_print_error ( param ,
" Record format used by '%s' is is not yet supported with repair/check " ,
filename ) ;
param - > error_printed = 0 ;
error = 1 ;
goto end2 ;
}
/* We can't do parallell repair with BLOCK_RECORD yet */
if ( param - > testflag & ( T_REP_BY_SORT | T_REP_PARALLEL ) )
{
param - > testflag & = ~ ( T_REP_BY_SORT | T_REP_PARALLEL ) ;
param - > testflag | = T_REP ;
}
2007-01-18 21:38:14 +02:00
}
2006-04-11 16:45:10 +03:00
/*
Skip the checking of the file if :
We are using - - fast and the table is closed properly
We are using - - check - only - changed - tables and the table hasn ' t changed
*/
if ( param - > testflag & ( T_FAST | T_CHECK_ONLY_CHANGED ) )
{
2007-01-18 21:38:14 +02:00
my_bool need_to_check = ( maria_is_crashed ( info ) | |
share - > state . open_count ! = 0 ) ;
2006-04-11 16:45:10 +03:00
if ( ( param - > testflag & ( T_REP_ANY | T_SORT_RECORDS ) ) & &
( ( share - > state . changed & ( STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR ) | |
! ( param - > testflag & T_CHECK_ONLY_CHANGED ) ) ) )
need_to_check = 1 ;
if ( info - > s - > base . keys & & info - > state - > records )
{
if ( ( param - > testflag & T_STATISTICS ) & &
( share - > state . changed & STATE_NOT_ANALYZED ) )
need_to_check = 1 ;
if ( ( param - > testflag & T_SORT_INDEX ) & &
( share - > state . changed & STATE_NOT_SORTED_PAGES ) )
need_to_check = 1 ;
if ( ( param - > testflag & T_REP_BY_SORT ) & &
( share - > state . changed & STATE_NOT_OPTIMIZED_KEYS ) )
need_to_check = 1 ;
}
if ( ( param - > testflag & T_CHECK_ONLY_CHANGED ) & &
( share - > state . changed & ( STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR ) ) )
need_to_check = 1 ;
if ( ! need_to_check )
{
if ( ! ( param - > testflag & T_SILENT ) | | param - > testflag & T_INFO )
printf ( " MARIA file: %s is already checked \n " , filename ) ;
if ( maria_close ( info ) )
{
_ma_check_print_error ( param , " %d when closing MARIA-table '%s' " ,
my_errno , filename ) ;
DBUG_RETURN ( 1 ) ;
}
DBUG_RETURN ( 0 ) ;
}
}
if ( ( param - > testflag & ( T_REP_ANY | T_STATISTICS |
T_SORT_RECORDS | T_SORT_INDEX ) ) & &
( ( ( param - > testflag & T_UNPACK ) & &
share - > data_file_type = = COMPRESSED_RECORD ) | |
mi_uint2korr ( share - > state . header . state_info_length ) ! =
MARIA_STATE_INFO_SIZE | |
mi_uint2korr ( share - > state . header . base_info_length ) ! =
MARIA_BASE_INFO_SIZE | |
maria_is_any_intersect_keys_active ( param - > keys_in_use , share - > base . keys ,
~ share - > state . key_map ) | |
maria_test_if_almost_full ( info ) | |
info - > s - > state . header . file_version [ 3 ] ! = maria_file_magic [ 3 ] | |
( set_collation & &
2007-04-19 18:48:36 +03:00
set_collation - > number ! = share - > state . header . language ) ) )
2006-04-11 16:45:10 +03:00
{
if ( set_collation )
param - > language = set_collation - > number ;
if ( maria_recreate_table ( param , & info , filename ) )
{
VOID ( fprintf ( stderr ,
" MARIA-table '%s' is not fixed because of errors \n " ,
filename ) ) ;
return ( - 1 ) ;
}
recreate = 1 ;
if ( ! ( param - > testflag & T_REP_ANY ) )
{
param - > testflag | = T_REP_BY_SORT ; /* if only STATISTICS */
if ( ! ( param - > testflag & T_SILENT ) )
printf ( " - '%s' has old table-format. Recreating index \n " , filename ) ;
rep_quick | = T_QUICK ;
}
share = info - > s ;
share - > tot_locks - = share - > r_locks ;
share - > r_locks = 0 ;
}
if ( param - > testflag & T_DESCRIPT )
{
param - > total_files + + ;
param - > total_records + = info - > state - > records ;
param - > total_deleted + = info - > state - > del ;
descript ( param , info , filename ) ;
2007-04-19 18:48:36 +03:00
maria_close ( info ) ; /* Should always succeed */
return ( 0 ) ;
2006-04-11 16:45:10 +03:00
}
2007-04-19 18:48:36 +03:00
if ( ! stopwords_inited + + )
ft_init_stopwords ( ) ;
if ( ! ( param - > testflag & T_READONLY ) )
lock_type = F_WRLCK ; /* table is changed */
2006-04-11 16:45:10 +03:00
else
2007-04-19 18:48:36 +03:00
lock_type = F_RDLCK ;
if ( info - > lock_type = = F_RDLCK )
info - > lock_type = F_UNLCK ; /* Read only table */
if ( _ma_readinfo ( info , lock_type , 0 ) )
{
_ma_check_print_error ( param , " Can't lock indexfile of '%s', error: %d " ,
filename , my_errno ) ;
param - > error_printed = 0 ;
error = 1 ;
goto end2 ;
}
/*
_ma_readinfo ( ) has locked the table .
We mark the table as locked ( without doing file locks ) to be able to
use functions that only works on locked tables ( like row caching ) .
*/
maria_lock_database ( info , F_EXTRA_LCK ) ;
datafile = info - > dfile . file ;
if ( init_pagecache ( maria_pagecache , param - > use_buffers , 0 , 0 ,
maria_block_size ) = = 0 )
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
_ma_check_print_error ( param , " Can't initialize page cache with %lu memory " ,
( ulong ) param - > use_buffers ) ;
error = 1 ;
goto end2 ;
}
2006-04-11 16:45:10 +03:00
2007-04-19 18:48:36 +03:00
if ( param - > testflag & ( T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX ) )
{
if ( param - > testflag & T_REP_ANY )
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
ulonglong tmp = share - > state . key_map ;
maria_copy_keys_active ( share - > state . key_map , share - > base . keys ,
param - > keys_in_use ) ;
if ( tmp ! = share - > state . key_map )
info - > update | = HA_STATE_CHANGED ;
2006-04-11 16:45:10 +03:00
}
2007-04-19 18:48:36 +03:00
if ( rep_quick & &
maria_chk_del ( param , info , param - > testflag & ~ T_VERBOSE ) )
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
if ( param - > testflag & T_FORCE_CREATE )
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
rep_quick = 0 ;
_ma_check_print_info ( param , " Creating new data file \n " ) ;
2006-04-11 16:45:10 +03:00
}
2007-04-19 18:48:36 +03:00
else
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
error = 1 ;
_ma_check_print_error ( param ,
" Quick-recover aborted; Run recovery without switch 'q' " ) ;
2006-04-11 16:45:10 +03:00
}
}
2007-04-19 18:48:36 +03:00
if ( ! error )
2006-04-11 16:45:10 +03:00
{
2007-06-27 12:58:08 +02:00
/*
Tell the server ' s Recovery to ignore old REDOs on this table ; we don ' t
know what the log ' s end LSN is now , so we just let the server know
that it will have to find and store it .
WL#3071 Maria checkpoint
Finally this is the real checkpoint code.
It however exhibits unstabilities when a checkpoint runs concurrently
with data-modifying clients (table corruption, transaction log's
assertions) so for now a checkpoint is taken only at startup after
recovery and at shutdown, i.e. not in concurrent situations. Later
we will let it run periodically, as well as flush dirty pages
periodically (almost all needed code is there already, only pagecache
code is written but not committed).
WL#3072 Maria recovery
* replacing UNDO_ROW_PURGE with CLR_END; testing of those CLR_END via
ma_test2 which has INSERTs failing with duplicate keys.
* replaying of REDO_RENAME_TABLE
Now, off to test Recovery in ha_maria :)
BitKeeper/deleted/.del-ma_least_recently_dirtied.c:
Delete: storage/maria/ma_least_recently_dirtied.c
BitKeeper/deleted/.del-ma_least_recently_dirtied.h:
Delete: storage/maria/ma_least_recently_dirtied.h
storage/maria/Makefile.am:
compile Checkpoint module
storage/maria/ha_maria.cc:
When ha_maria starts, do a recovery from last checkpoint.
Take a checkpoint when that recovery has ended and when ha_maria
shuts down cleanly.
storage/maria/ma_blockrec.c:
* even if my_sync() fails we have to my_close() (otherwise we leak
a descriptor)
* UNDO_ROW_PURGE is replaced by a simple CLR_END for UNDO_ROW_INSERT,
as promised in the old comment; it gives us skipping during the
UNDO phase.
storage/maria/ma_check.c:
All REDOs before create_rename_lsn are ignored by Recovery. So
create_rename_lsn must be set only after all data/index has been
flushed and forced to disk. We thus move write_log_record_for_repair()
to after _ma_flush_tables_files_after_repair().
storage/maria/ma_checkpoint.c:
Checkpoint module.
storage/maria/ma_checkpoint.h:
optional argument if caller wants a thread to periodically take
checkpoints and flush dirty pages.
storage/maria/ma_create.c:
* no need to init some vars as the initial bzero(share) takes care of this.
* update to new function's name
* even if we fail in my_sync() we have to my_close()
storage/maria/ma_extra.c:
Checkpoint reads share->last_version under intern_lock, so we make
maria_extra() update it under intern_lock. THR_LOCK_maria still needed
because of _ma_test_if_reopen().
storage/maria/ma_init.c:
destroy checkpoint module when Maria shuts down.
storage/maria/ma_loghandler.c:
* UNDO_ROW_PURGE gone (see ma_blockrec.c)
* we need to remember the LSN of the LOGREC_FILE_ID for a share,
because this LSN is needed into the checkpoint record (Recovery wants
to know the validity domain of an id->name mapping)
* translog_get_horizon_no_lock() needed for Checkpoint
* comment about failing assertion (Sanja knows)
* translog_init_reader_data() thought that translog_read_record_header_scan()
returns 0 in case of error, but 0 just means "0-length header".
* translog_assign_id_to_share() now needs the MARIA_HA because
LOGREC_FILE_ID uses a log-write hook.
* Verify that (de)assignment of share->id happens only under intern_lock,
as Checkpoint reads this id with intern_lock.
* translog_purge() can accept TRANSLOG_ADDRESS, not necessarily
a real LSN.
storage/maria/ma_loghandler.h:
prototype updates
storage/maria/ma_open.c:
no need to initialize "res"
storage/maria/ma_pagecache.c:
When taking a checkpoint, we don't need to know the maximum rec_lsn
of dirty pages; this LSN was intended to be used in the two-checkpoint
rule, but last_checkpoint_lsn is as good.
4 bytes for stored_list_size is enough as PAGECACHE::blocks (number
of blocks which the pagecache can contain) is int.
storage/maria/ma_pagecache.h:
new prototype
storage/maria/ma_recovery.c:
* added replaying of REDO_RENAME_TABLE
* UNDO_ROW_PURGE gone (see ma_blockrec.c), replaced by CLR_END
* Recovery from the last checkpoint record now possible
* In new_table() we skip the table if the id->name mapping is older than
create_rename_lsn (mapping dates from lsn_of_file_id).
* in get_MARIA_HA_from_REDO_record() we skip the record
if the id->name mapping is newer than the record (can happen if processing
a record which is before the checkpoint record).
* parse_checkpoint_record() has to return a LSN, that's what caller expects
storage/maria/ma_rename.c:
new function's name; log end zeroes of tables' names (ease recovery)
storage/maria/ma_test2.c:
* equivalent of ma_test1's --test-undo added (named -u here).
* -t=1 now stops right after creating the table, so that
we can test undoing of INSERTs with duplicate keys (which tests the
CLR_END logged by _ma_write_abort_block_record()).
storage/maria/ma_test_recovery.expected:
Result of testing undoing of INSERTs with duplicate keys; there are
some differences in maria_chk -dvv but they are normal (removing
records does not shrink data/index file, does not put back the
"analyzed, optimized keys"(etc) index state.
storage/maria/ma_test_recovery:
Test undoing of INSERTs with duplicate keys, using ma_test2;
when such INSERT happens, it logs REDO_INSERT, UNDO_INSERT, REDO_DELETE,
CLR_END; we abort after that, and test that CLR_END causes recovery
to jump over UNDO_INSERT.
storage/maria/ma_write.c:
comment
storage/maria/maria_chk.c:
comment
storage/maria/maria_def.h:
* a new bit in MARIA_SHARE::in_checkpoint, used to build a list
of unique shares during Checkpoint.
* MARIA_SHARE::lsn_of_file_id added: the LSN of the last LOGREC_FILE_ID
for this share; needed to know to which LSN domain the mappings
found in the Checkpoint record apply (new mappings should not apply
to old REDOs).
storage/maria/trnman.c:
* small changes to how trnman_collect_transactions() fills its buffer;
it also uses a non-dummy lsn_read_non_atomic() found in ma_checkpoint.h
2007-09-12 11:27:34 +02:00
This is the only case where create_rename_lsn can be a horizon and not
a LSN .
2007-06-27 12:58:08 +02:00
*/
Maria:
* Don't modify share->base.born_transactional; now it is a value carved
in stone at creation time. share->now_transactional is what can be
modified: it starts at born_transactional, can become false during
ALTER TABLE (when we want no logging), and restored later.
* Not resetting create_rename_lsn to 0 during delete_all or repair.
* when we temporarily disable transactionality, we also change
the page type to PAGECACHE_PLAIN_PAGE: it bypasses some work in the
page cache (optimization), and avoids assertions related to LSNs.
* Disable INSERT DELAYED for transactional tables, because
durability could not be guaranteed (insertion may even not happen)
mysys/mf_keycache.c:
comment
storage/maria/ha_maria.cc:
* a transactional table cannot do INSERT DELAYED
* ha_maria::save_transactional not needed anymore, as now instead
we don't modify MARIA_SHARE::MARIA_BASE_INFO::born_transactional
(born_transactional plays the role of save_transactional), and modify
MARIA_SHARE::now_transactional.
* REPAIR_TABLE log record is now logged by maria_repair()
* comment why we rely on born_transactional to know if we should
skipping a transaction.
* putting together two if()s which test for F_UNLCK
storage/maria/ha_maria.h:
ha_maria::save_transactional not needed anymore (moved to the C layer)
storage/maria/ma_blockrec.c:
* For the block record's code (writing/updating/deleting records),
all that counts is now_transactional, not born_transactional.
* As we now set the page type to PAGECACHE_PLAIN_PAGE for tables
which have now_transactional==FALSE, pagecache will not expect
a meaningful LSN for them in pagecache_unlock_by_link(), so
we can pass it LSN_IMPOSSIBLE.
storage/maria/ma_check.c:
* writing LOGREC_REPAIR_TABLE moves from ha_maria::repair()
to maria_repair(), sounds cleaner (less functions to export).
* when opening a table during REPAIR, don't use the realpath-ed name,
as this may fail if the table has symlinked files (maria_open()
would try to find the data and index file in the directory
of unique_file_name, it would fail if data and index files are in
different dirs); use the unresolved name, open_file_name, which is
the argument which was passed to the maria_open() which created 'info'.
storage/maria/ma_close.c:
assert that when a statement is done with a table, it cleans up
storage/maria/ma_create.c:
new name
storage/maria/ma_delete_all.c:
* using now_transactional
* no reason to reset create_rename_lsn during delete_all (a bug);
also no reason to do it during repair: it was put there because
a positive create_rename_lsn caused a call to check_and_set_lsn()
which asserted in DBUG_ASSERT(block->type == PAGECACHE_LSN_PAGE);
first solution was to use LSN_IMPOSSIBLE in _ma_unpin_all_pages() if
not transactional; but then in the case of ALTER TABLE, with
transactionality temporarily disabled, it asserted in
DBUG_ASSERT(LSN_VALID(lsn)) in pagecache_fwrite() (PAGECACHE_LSN_PAGE
page with zero LSN - bad). The additional solution is to use
PAGECACHE_PLAIN_PAGE when we disable transactionality temporarily: this
avoids checks on the LSN, and also bypasses (optimization) the "flush
log up to LSN" call when the pagecache flushes our page (in other
words, no WAL needed).
storage/maria/ma_delete_table.c:
use now_transactional
storage/maria/ma_locking.c:
assert that when a statement is done with a table, it cleans up.
storage/maria/ma_loghandler.c:
* now_transactional should be used to test if we want a log record.
* Assertions to make sure dummy_transaction_object is not spoilt
by its many users.
storage/maria/ma_open.c:
base.transactional -> base.born_transactional
storage/maria/ma_pagecache.c:
missing name for page's type. Comment for future.
storage/maria/ma_rename.c:
use now_transactional
storage/maria/maria_chk.c:
use born_transactional
storage/maria/maria_def.h:
MARIA_BASE_INFO::transactional renamed to born_transactional.
MARIA_SHARE::now_transactional introduced.
_ma_repair_write_log_record() is made local to ma_check.c.
Macros to temporarily disable, and re-enable, transactionality for a
table.
storage/maria/maria_read_log.c:
assertions and using the new macros. Adding a forgotten resetting
when we finally close all tables.
2007-07-03 15:20:41 +02:00
if ( share - > base . born_transactional )
WL#3071 Maria checkpoint
Finally this is the real checkpoint code.
It however exhibits unstabilities when a checkpoint runs concurrently
with data-modifying clients (table corruption, transaction log's
assertions) so for now a checkpoint is taken only at startup after
recovery and at shutdown, i.e. not in concurrent situations. Later
we will let it run periodically, as well as flush dirty pages
periodically (almost all needed code is there already, only pagecache
code is written but not committed).
WL#3072 Maria recovery
* replacing UNDO_ROW_PURGE with CLR_END; testing of those CLR_END via
ma_test2 which has INSERTs failing with duplicate keys.
* replaying of REDO_RENAME_TABLE
Now, off to test Recovery in ha_maria :)
BitKeeper/deleted/.del-ma_least_recently_dirtied.c:
Delete: storage/maria/ma_least_recently_dirtied.c
BitKeeper/deleted/.del-ma_least_recently_dirtied.h:
Delete: storage/maria/ma_least_recently_dirtied.h
storage/maria/Makefile.am:
compile Checkpoint module
storage/maria/ha_maria.cc:
When ha_maria starts, do a recovery from last checkpoint.
Take a checkpoint when that recovery has ended and when ha_maria
shuts down cleanly.
storage/maria/ma_blockrec.c:
* even if my_sync() fails we have to my_close() (otherwise we leak
a descriptor)
* UNDO_ROW_PURGE is replaced by a simple CLR_END for UNDO_ROW_INSERT,
as promised in the old comment; it gives us skipping during the
UNDO phase.
storage/maria/ma_check.c:
All REDOs before create_rename_lsn are ignored by Recovery. So
create_rename_lsn must be set only after all data/index has been
flushed and forced to disk. We thus move write_log_record_for_repair()
to after _ma_flush_tables_files_after_repair().
storage/maria/ma_checkpoint.c:
Checkpoint module.
storage/maria/ma_checkpoint.h:
optional argument if caller wants a thread to periodically take
checkpoints and flush dirty pages.
storage/maria/ma_create.c:
* no need to init some vars as the initial bzero(share) takes care of this.
* update to new function's name
* even if we fail in my_sync() we have to my_close()
storage/maria/ma_extra.c:
Checkpoint reads share->last_version under intern_lock, so we make
maria_extra() update it under intern_lock. THR_LOCK_maria still needed
because of _ma_test_if_reopen().
storage/maria/ma_init.c:
destroy checkpoint module when Maria shuts down.
storage/maria/ma_loghandler.c:
* UNDO_ROW_PURGE gone (see ma_blockrec.c)
* we need to remember the LSN of the LOGREC_FILE_ID for a share,
because this LSN is needed into the checkpoint record (Recovery wants
to know the validity domain of an id->name mapping)
* translog_get_horizon_no_lock() needed for Checkpoint
* comment about failing assertion (Sanja knows)
* translog_init_reader_data() thought that translog_read_record_header_scan()
returns 0 in case of error, but 0 just means "0-length header".
* translog_assign_id_to_share() now needs the MARIA_HA because
LOGREC_FILE_ID uses a log-write hook.
* Verify that (de)assignment of share->id happens only under intern_lock,
as Checkpoint reads this id with intern_lock.
* translog_purge() can accept TRANSLOG_ADDRESS, not necessarily
a real LSN.
storage/maria/ma_loghandler.h:
prototype updates
storage/maria/ma_open.c:
no need to initialize "res"
storage/maria/ma_pagecache.c:
When taking a checkpoint, we don't need to know the maximum rec_lsn
of dirty pages; this LSN was intended to be used in the two-checkpoint
rule, but last_checkpoint_lsn is as good.
4 bytes for stored_list_size is enough as PAGECACHE::blocks (number
of blocks which the pagecache can contain) is int.
storage/maria/ma_pagecache.h:
new prototype
storage/maria/ma_recovery.c:
* added replaying of REDO_RENAME_TABLE
* UNDO_ROW_PURGE gone (see ma_blockrec.c), replaced by CLR_END
* Recovery from the last checkpoint record now possible
* In new_table() we skip the table if the id->name mapping is older than
create_rename_lsn (mapping dates from lsn_of_file_id).
* in get_MARIA_HA_from_REDO_record() we skip the record
if the id->name mapping is newer than the record (can happen if processing
a record which is before the checkpoint record).
* parse_checkpoint_record() has to return a LSN, that's what caller expects
storage/maria/ma_rename.c:
new function's name; log end zeroes of tables' names (ease recovery)
storage/maria/ma_test2.c:
* equivalent of ma_test1's --test-undo added (named -u here).
* -t=1 now stops right after creating the table, so that
we can test undoing of INSERTs with duplicate keys (which tests the
CLR_END logged by _ma_write_abort_block_record()).
storage/maria/ma_test_recovery.expected:
Result of testing undoing of INSERTs with duplicate keys; there are
some differences in maria_chk -dvv but they are normal (removing
records does not shrink data/index file, does not put back the
"analyzed, optimized keys"(etc) index state.
storage/maria/ma_test_recovery:
Test undoing of INSERTs with duplicate keys, using ma_test2;
when such INSERT happens, it logs REDO_INSERT, UNDO_INSERT, REDO_DELETE,
CLR_END; we abort after that, and test that CLR_END causes recovery
to jump over UNDO_INSERT.
storage/maria/ma_write.c:
comment
storage/maria/maria_chk.c:
comment
storage/maria/maria_def.h:
* a new bit in MARIA_SHARE::in_checkpoint, used to build a list
of unique shares during Checkpoint.
* MARIA_SHARE::lsn_of_file_id added: the LSN of the last LOGREC_FILE_ID
for this share; needed to know to which LSN domain the mappings
found in the Checkpoint record apply (new mappings should not apply
to old REDOs).
storage/maria/trnman.c:
* small changes to how trnman_collect_transactions() fills its buffer;
it also uses a non-dummy lsn_read_non_atomic() found in ma_checkpoint.h
2007-09-12 11:27:34 +02:00
share - > state . create_rename_lsn = share - > state . is_of_horizon =
- WL#3072 Maria Recovery:
Recovery of state.records (the count of records which is stored into
the header of the index file). For that, state.is_of_lsn is introduced;
logic is explained in ma_recovery.c (look for "Recovery of the state").
The net gain is that in case of crash, we now recover state.records,
and it is idempotent (ma_test_recovery tests it).
state.checksum is not recovered yet, mail sent for discussion.
- WL#3071 Maria Checkpoint: preparation for it, by protecting
all modifications of the state in memory or on disk with intern_lock
(with the exception of the really-often-modified state.records,
which is now protected with the log's lock, see ma_recovery.c
(look for "Recovery of the state"). Also, if maria_close() sees that
Checkpoint is looking at this table it will not my_free() the share.
- don't compute row's checksum twice in case of UPDATE (correction
to a bugfix I made yesterday).
storage/maria/ha_maria.cc:
protect state write with intern_lock (against Checkpoint)
storage/maria/ma_blockrec.c:
* don't reset trn->rec_lsn in _ma_unpin_all_pages(), because it
should wait until we have corrected the allocation in the bitmap
(as the REDO can serve to correct the allocation during Recovery);
introducing _ma_finalize_row() for that.
* In a changeset yesterday I moved computation of the checksum
into write_block_record(), to fix a bug in UPDATE. Now I notice
that maria_update() already computes the checksum, it's just that
it puts it into info->cur_row while _ma_update_block_record()
uses info->new_row; so, removing the checksum computation from
write_block_record(), putting it back into allocate_and_write_block_record()
(which is called only by INSERT and UNDO_DELETE), and copying
cur_row->checksum into new_row->checksum in _ma_update_block_record().
storage/maria/ma_check.c:
new prototypes, they will take intern_lock when writing the state;
also take intern_lock when changing share->kfile. In both cases
this is to protect against Checkpoint reading/writing the state or reading
kfile at the same time.
Not updating create_rename_lsn directly at end of write_log_record_for_repair()
as it wouldn't have intern_lock.
storage/maria/ma_close.c:
Checkpoint builds a list of shares (under THR_LOCK_maria), then it
handles each such share (under intern_lock) (doing flushing etc);
if maria_close() freed this share between the two, Checkpoint
would see a bad pointer. To avoid this, when building the list Checkpoint
marks each share, so that maria_close() knows it should not free it
and Checkpoint will free it itself.
Extending the zone covered by intern_lock to protect against
Checkpoint reading kfile, writing state.
storage/maria/ma_create.c:
When we update create_rename_lsn, we also update is_of_lsn to
the same value: it is logical, and allows us to test in maria_open()
that the former is not bigger than the latter (the contrary is a sign
of index header corruption, or severe logging bug which hinders
Recovery, table needs a repair).
_ma_update_create_rename_lsn_on_disk() also writes is_of_lsn;
it now operates under intern_lock (protect against Checkpoint),
a shortcut function is available for cases where acquiring
intern_lock is not needed (table's creation or first open).
storage/maria/ma_delete.c:
if table is transactional, "records" is already decremented
when logging UNDO_ROW_DELETE.
storage/maria/ma_delete_all.c:
comments
storage/maria/ma_extra.c:
Protect modifications of the state, in memory and/or on disk,
with intern_lock, against a concurrent Checkpoint.
When state goes to disk, update it's is_of_lsn (by calling
the new _ma_state_info_write()).
In HA_EXTRA_FORCE_REOPEN, don't set share->changed to 0 (undoing
a change I made a few days ago) and ASK_MONTY
storage/maria/ma_locking.c:
no real code change here.
storage/maria/ma_loghandler.c:
Log-write-hooks for updating "state.records" under log's mutex
when writing/updating/deleting a row or deleting all rows.
storage/maria/ma_loghandler_lsn.h:
merge (make LSN_ERROR and LSN_REPAIRED_BY_MARIA_CHK different)
storage/maria/ma_open.c:
When opening a table verify that is_of_lsn >= create_rename_lsn; if
false the header must be corrupted.
_ma_state_info_write() is split in two: _ma_state_info_write_sub()
which is the old _ma_state_info_write(), and _ma_state_info_write()
which additionally takes intern_lock if requested (to protect
against Checkpoint) and updates is_of_lsn.
_ma_open_keyfile() should change kfile.file under intern_lock
to protect Checkpoint from reading a wrong kfile.file.
storage/maria/ma_recovery.c:
Recovery of state.records: when the REDO phase sees UNDO_ROW_INSERT
which has a LSN > state.is_of_lsn it increments state.records.
Same for UNDO_ROW_DELETE and UNDO_ROW_PURGE.
When closing a table during Recovery, we know its state is at least
as new as the current log record we are looking at, so increase
is_of_lsn to the LSN of the current log record.
storage/maria/ma_rename.c:
update for new behaviour of _ma_update_create_rename_lsn_on_disk().
storage/maria/ma_test1.c:
update to new prototype
storage/maria/ma_test2.c:
update to new prototype (actually prototype was changed days ago,
but compiler does not complain about the extra argument??)
storage/maria/ma_test_recovery.expected:
new result file of ma_test_recovery. Improvements: record
count read from index's header is now always correct.
storage/maria/ma_test_recovery:
"rm" fails if file does not exist. Redirect stderr of script.
storage/maria/ma_write.c:
if table is transactional, "records" is already incremented when
logging UNDO_ROW_INSERT. Comments.
storage/maria/maria_chk.c:
update is_of_lsn too
storage/maria/maria_def.h:
- MARIA_STATE_INFO::is_of_lsn which is used by Recovery. It is stored
into the index file's header.
- Checkpoint can now mark a table as "don't free this", and maria_close()
can reply "ok then you will free it".
- new functions
storage/maria/maria_pack.c:
update for new name
2007-09-07 15:02:30 +02:00
LSN_REPAIRED_BY_MARIA_CHK ;
2007-04-19 18:48:36 +03:00
if ( ( param - > testflag & ( T_REP_BY_SORT | T_REP_PARALLEL ) ) & &
( maria_is_any_key_active ( share - > state . key_map ) | |
( rep_quick & & ! param - > keys_in_use & & ! recreate ) ) & &
maria_test_if_sort_rep ( info , info - > state - > records ,
info - > s - > state . key_map ,
param - > force_sort ) )
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
if ( param - > testflag & T_REP_BY_SORT )
error = maria_repair_by_sort ( param , info , filename , rep_quick ) ;
else
error = maria_repair_parallel ( param , info , filename , rep_quick ) ;
state_updated = 1 ;
2006-04-11 16:45:10 +03:00
}
2007-04-19 18:48:36 +03:00
else if ( param - > testflag & T_REP_ANY )
error = maria_repair ( param , info , filename , rep_quick ) ;
}
if ( ! error & & param - > testflag & T_SORT_RECORDS )
{
/*
The data file is nowadays reopened in the repair code so we should
soon remove the following reopen - code
*/
# ifndef TO_BE_REMOVED
if ( param - > out_flag & O_NEW_DATA )
{ /* Change temp file to org file */
VOID ( my_close ( info - > dfile . file , MYF ( MY_WME ) ) ) ; /* Close new file */
error | = maria_change_to_newfile ( filename , MARIA_NAME_DEXT , DATA_TMP_EXT ,
MYF ( 0 ) ) ;
if ( _ma_open_datafile ( info , info - > s , - 1 ) )
error = 1 ;
param - > out_flag & = ~ O_NEW_DATA ; /* We are using new datafile */
param - > read_cache . file = info - > dfile . file ;
2006-04-11 16:45:10 +03:00
}
2007-04-19 18:48:36 +03:00
# endif
if ( ! error )
2006-04-11 16:45:10 +03:00
{
2007-04-19 18:48:36 +03:00
uint key ;
/*
We can ' t update the index in maria_sort_records if we have a
prefix compressed or fulltext index
*/
my_bool update_index = 1 ;
for ( key = 0 ; key < share - > base . keys ; key + + )
if ( share - > keyinfo [ key ] . flag & ( HA_BINARY_PACK_KEY | HA_FULLTEXT ) )
update_index = 0 ;
error = maria_sort_records ( param , info , filename , param - > opt_sort_key ,
/* what is the following parameter for ? */
( my_bool ) ! ( param - > testflag & T_REP ) ,
update_index ) ;
datafile = info - > dfile . file ; /* This is now locked */
if ( ! error & & ! update_index )
{
if ( param - > verbose )
puts ( " Table had a compressed index; We must now recreate the index " ) ;
error = maria_repair_by_sort ( param , info , filename , 1 ) ;
}
2006-04-11 16:45:10 +03:00
}
}
2007-04-19 18:48:36 +03:00
if ( ! error & & param - > testflag & T_SORT_INDEX )
error = maria_sort_index ( param , info , filename ) ;
if ( ! error )
share - > state . changed & = ~ ( STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR ) ;
else
maria_mark_crashed ( info ) ;
}
else if ( ( param - > testflag & T_CHECK ) | | ! ( param - > testflag & T_AUTO_INC ) )
{
if ( ! ( param - > testflag & T_SILENT ) | | param - > testflag & T_INFO )
printf ( " Checking MARIA file: %s \n " , filename ) ;
if ( ! ( param - > testflag & T_SILENT ) )
printf ( " Data records: %7s Deleted blocks: %7s \n " ,
llstr ( info - > state - > records , llbuff ) ,
llstr ( info - > state - > del , llbuff2 ) ) ;
error = maria_chk_status ( param , info ) ;
maria_intersect_keys_active ( share - > state . key_map , param - > keys_in_use ) ;
error = maria_chk_size ( param , info ) ;
if ( ! error | | ! ( param - > testflag & ( T_FAST | T_FORCE_CREATE ) ) )
error | = maria_chk_del ( param , info , param - > testflag ) ;
if ( ( ! error | | ( ! ( param - > testflag & ( T_FAST | T_FORCE_CREATE ) ) & &
! param - > start_check_pos ) ) )
{
error | = maria_chk_key ( param , info ) ;
if ( ! error & & ( param - > testflag & ( T_STATISTICS | T_AUTO_INC ) ) )
error = maria_update_state_info ( param , info ,
( ( param - > testflag & T_STATISTICS ) ?
UPDATE_STAT : 0 ) |
( ( param - > testflag & T_AUTO_INC ) ?
UPDATE_AUTO_INC : 0 ) ) ;
}
if ( ( ! rep_quick & & ! error ) | |
! ( param - > testflag & ( T_FAST | T_FORCE_CREATE ) ) )
{
VOID ( init_io_cache ( & param - > read_cache , datafile ,
( uint ) param - > read_buffer_length ,
READ_CACHE ,
( param - > start_check_pos ?
param - > start_check_pos :
share - > pack . header_length ) ,
1 ,
MYF ( MY_WME ) ) ) ;
maria_lock_memory ( param ) ;
if ( ( info - > s - > data_file_type ! = STATIC_RECORD ) | |
( param - > testflag & ( T_EXTEND | T_MEDIUM ) ) )
error | = maria_chk_data_link ( param , info , param - > testflag & T_EXTEND ) ;
- speed optimization:
minimize writes to transactional Maria tables: don't write
data pages, state, and open_count at the end of each statement.
Data pages will be written by a background thread periodically.
State will be written by Checkpoint periodically.
open_count serves to detect when a table is potentially damaged
due to an unclean mysqld stop, but thanks to recovery an unclean
mysqld stop will be corrected and so open_count becomes useless.
As state is written less often, it is often obsolete on disk,
we thus should avoid to read it from disk.
- by removing the data page writes above, it is necessary to put
it back at the start of some statements like check, repair and
delete_all. It was already necessary in fact (see ma_delete_all.c).
- disabling CACHE INDEX on Maria tables for now (fixes crash
of test 'key_cache' when run with --default-storage-engine=maria).
- correcting some fishy code in maria_extra.c (we possibly could lose
index pages when doing a DROP TABLE under Windows, in theory).
storage/maria/ha_maria.cc:
disable CACHE INDEX in Maria for now (there is a single cache for now),
it crashes and it's not a priority
storage/maria/ma_bitmap.c:
debug message
storage/maria/ma_check.c:
The statement before maria_repair() may not flush state,
so it needs to be done by maria_repair() (indeed this function
uses maria_open(HA_OPEN_COPY) so reads state from disk,
so needs to find it up-to-date on disk).
For safety (but normally this is not needed) we remove index blocks
out of the cache before repairing.
_ma_flush_blocks() becomes _ma_flush_table_files_after_repair():
it now additionally flushes the data file and state and syncs files.
As a side effect, the assertion "no WRITE_CACHE_USED" from
_ma_flush_table_files() fired so we move all end_io_cache() done
at the end of repair to before the calls to _ma_flush_table_files_after_repair().
storage/maria/ma_close.c:
when closing a transactional table, we fsync it. But we need to
do this only after writing its state.
We need to write the state at close time only for transactional
tables (the other tables do that at last unlock).
Putting back the O_RDONLY||crashed condition which I had
removed earlier.
Unmap the file before syncing it (does not matter now as Maria
does not use mmap)
storage/maria/ma_delete_all.c:
need to flush data pages before chsize-ing it. Was needed even when
we flushed data pages at the end of each statement, because we didn't
anyway do it if under LOCK TABLES: the change here thus fixes this bug:
create table t(a int) engine=maria;lock tables t write;
insert into t values(1);delete from t;unlock tables;check table t;
"Size of datafile is: 16384 Should be: 8192"
(an obsolete page went to disk after the chsize(), at unlock time).
storage/maria/ma_extra.c:
When doing share->last_version=0, we make the MARIA_SHARE-in-memory
invisible to future openers, so need to have an up-to-date state
on disk for them. The same way, future openers will reopen the data
and index file, so they will not find our cached blocks, so we
need to flush them to disk.
In HA_EXTRA_FORCE_REOPEN, this probably happens naturally as all
tables normally get closed, we however add a safety flush.
In HA_EXTRA_PREPARE_FOR_RENAME, we need to do the flushing. On
Windows we additionally need to close files.
In HA_EXTRA_PREPARE_FOR_DROP, we don't need to flush anything but
remove dirty cached blocks from memory. On Windows we need to close
files.
Closing files forces us to sync them before (requirement for transactional
tables).
For mutex reasons (don't lock intern_lock twice), we move
maria_lock_database() and _ma_decrement_open_count() first in the list
of operations.
Flush also data file in HA_EXTRA_FLUSH.
storage/maria/ma_locking.c:
For transactional tables:
- don't write data pages / state at unlock time;
as a consequence, "share->changed=0" cannot be done.
- don't write state in _ma_writeinfo()
- don't maintain open_count on disk (Recovery corrects the table in case of crash
anyway, and we gain speed by not writing open_count to disk),
For non-transactional tables, flush the state at unlock only
if the table was changed (optimization).
Code which read the state from disk is relevant only with
external locking, we disable it (if want to re-enable it, it shouldn't
for transactional tables as state on disk may be obsolete (such tables
does not flush state at unlock anymore).
The comment "We have to flush the write cache" is now wrong because
maria_lock_database(F_UNLCK) now happens before thr_unlock(), and
we are not using external locking.
storage/maria/ma_open.c:
_ma_state_info_read() is only used in ma_open.c, making it static
storage/maria/ma_recovery.c:
set MARIA_SHARE::changed to TRUE when we are going to apply a
REDO/UNDO, so that the state gets flushed at close.
storage/maria/ma_test_recovery.expected:
Changes introduced by this patch:
- good: the "open" (table open, not properly closed) is gone,
it was pointless for a recovered table
- bad: stemming from different moments of writing the index's state
probably (_ma_writeinfo() used to write the state after every row
write in ma_test* programs, doesn't anymore as the table is
transactional): some differences in indexes (not relevant as we don't
yet have recovery for them); some differences in count of records
(changed from a wrong value to another wrong value) (not relevant
as we don't recover this count correctly yet anyway, though
a patch will be pushed soon).
storage/maria/ma_test_recovery:
for repeatable output, no names of varying directories.
storage/maria/maria_chk.c:
function renamed
storage/maria/maria_def.h:
Function became local to ma_open.c. Function renamed.
2007-09-06 16:53:26 +02:00
error | = _ma_flush_table_files_after_repair ( param , info ) ;
2007-04-19 18:48:36 +03:00
VOID ( end_io_cache ( & param - > read_cache ) ) ;
}
if ( ! error )
{
if ( ( share - > state . changed & STATE_CHANGED ) & &
( param - > testflag & T_UPDATE_STATE ) )
info - > update | = HA_STATE_CHANGED | HA_STATE_ROW_CHANGED ;
share - > state . changed & = ~ ( STATE_CHANGED | STATE_CRASHED |
STATE_CRASHED_ON_REPAIR ) ;
}
else if ( ! maria_is_crashed ( info ) & &
( param - > testflag & T_UPDATE_STATE ) )
{ /* Mark crashed */
maria_mark_crashed ( info ) ;
info - > update | = HA_STATE_CHANGED | HA_STATE_ROW_CHANGED ;
}
2006-04-11 16:45:10 +03:00
}
2007-04-19 18:48:36 +03:00
2006-04-11 16:45:10 +03:00
if ( ( param - > testflag & T_AUTO_INC ) | |
( ( param - > testflag & T_REP_ANY ) & & info - > s - > base . auto_key ) )
_ma_update_auto_increment_key ( param , info ,
( my_bool ) ! test ( param - > testflag & T_AUTO_INC ) ) ;
2007-04-19 18:48:36 +03:00
if ( info - > update & HA_STATE_CHANGED & & ! ( param - > testflag & T_READONLY ) )
error | = maria_update_state_info ( param , info ,
UPDATE_OPEN_COUNT |
( ( ( param - > testflag & T_REP_ANY ) ?
UPDATE_TIME : 0 ) |
( state_updated ? UPDATE_STAT : 0 ) |
( ( param - > testflag & T_SORT_RECORDS ) ?
UPDATE_SORT : 0 ) ) ) ;
info - > update & = ~ HA_STATE_CHANGED ;
2006-04-11 16:45:10 +03:00
maria_lock_database ( info , F_UNLCK ) ;
2007-04-19 18:48:36 +03:00
2006-04-11 16:45:10 +03:00
end2 :
2007-04-19 18:48:36 +03:00
end_pagecache ( maria_pagecache , 1 ) ;
2006-04-11 16:45:10 +03:00
if ( maria_close ( info ) )
{
2007-04-19 18:48:36 +03:00
_ma_check_print_error ( param , " %d when closing MARIA-table '%s' " ,
my_errno , filename ) ;
2006-04-11 16:45:10 +03:00
DBUG_RETURN ( 1 ) ;
}
if ( error = = 0 )
{
if ( param - > out_flag & O_NEW_DATA )
error | = maria_change_to_newfile ( filename , MARIA_NAME_DEXT , DATA_TMP_EXT ,
2007-01-18 21:38:14 +02:00
( ( param - > testflag & T_BACKUP_DATA ) ?
MYF ( MY_REDEL_MAKE_BACKUP ) : MYF ( 0 ) ) ) ;
2006-04-11 16:45:10 +03:00
if ( param - > out_flag & O_NEW_INDEX )
2007-01-18 21:38:14 +02:00
error | = maria_change_to_newfile ( filename , MARIA_NAME_IEXT , INDEX_TMP_EXT ,
MYF ( 0 ) ) ;
2006-04-11 16:45:10 +03:00
}
VOID ( fflush ( stdout ) ) ; VOID ( fflush ( stderr ) ) ;
if ( param - > error_printed )
{
if ( param - > testflag & ( T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX ) )
{
VOID ( fprintf ( stderr ,
" MARIA-table '%s' is not fixed because of errors \n " ,
filename ) ) ;
if ( param - > testflag & T_REP_ANY )
VOID ( fprintf ( stderr ,
" Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag \n " ) ) ;
}
else if ( ! ( param - > error_printed & 2 ) & &
! ( param - > testflag & T_FORCE_CREATE ) )
VOID ( fprintf ( stderr ,
" MARIA-table '%s' is corrupted \n Fix it using switch \" -r \" or \" -o \" \n " ,
filename ) ) ;
}
else if ( param - > warning_printed & &
! ( param - > testflag & ( T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
T_FORCE_CREATE ) ) )
VOID ( fprintf ( stderr , " MARIA-table '%s' is usable but should be fixed \n " ,
filename ) ) ;
VOID ( fflush ( stderr ) ) ;
DBUG_RETURN ( error ) ;
2007-01-18 21:38:14 +02:00
} /* maria_chk */
2006-04-11 16:45:10 +03:00
2007-01-18 21:38:14 +02:00
/* Write info about table */
2006-04-11 16:45:10 +03:00
2007-07-02 20:45:15 +03:00
static void descript ( HA_CHECK * param , register MARIA_HA * info , char * name )
2006-04-11 16:45:10 +03:00
{
2007-04-19 13:18:56 +03:00
uint key , keyseg_nr , field ;
2006-04-11 16:45:10 +03:00
reg3 MARIA_KEYDEF * keyinfo ;
reg2 HA_KEYSEG * keyseg ;
reg4 const char * text ;
char buff [ 160 ] , length [ 10 ] , * pos , * end ;
enum en_fieldtype type ;
MARIA_SHARE * share = info - > s ;
char llbuff [ 22 ] , llbuff2 [ 22 ] ;
DBUG_ENTER ( " describe " ) ;
2007-08-29 09:03:10 +03:00
if ( param - > testflag & T_VERY_SILENT )
{
longlong checksum = info - > state - > checksum ;
if ( ! ( share - > options & ( HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD ) ) )
checksum = 0 ;
printf ( " %s %s %s \n " , name , llstr ( info - > state - > records , llbuff ) ,
llstr ( checksum , llbuff2 ) ) ;
DBUG_VOID_RETURN ;
}
2007-01-18 21:38:14 +02:00
printf ( " \n MARIA file: %s \n " , name ) ;
printf ( " Record format: %s \n " , record_formats [ share - > data_file_type ] ) ;
2006-04-11 16:45:10 +03:00
printf ( " Character set: %s (%d) \n " ,
get_charset_name ( share - > state . header . language ) ,
share - > state . header . language ) ;
if ( param - > testflag & T_VERBOSE )
{
printf ( " File-version: %d \n " ,
( int ) share - > state . header . file_version [ 3 ] ) ;
if ( share - > state . create_time )
{
get_date ( buff , 1 , share - > state . create_time ) ;
printf ( " Creation time: %s \n " , buff ) ;
}
if ( share - > state . check_time )
{
get_date ( buff , 1 , share - > state . check_time ) ;
printf ( " Recover time: %s \n " , buff ) ;
}
pos = buff ;
if ( share - > state . changed & STATE_CRASHED )
strmov ( buff , " crashed " ) ;
else
{
if ( share - > state . open_count )
pos = strmov ( pos , " open, " ) ;
if ( share - > state . changed & STATE_CHANGED )
pos = strmov ( pos , " changed, " ) ;
else
pos = strmov ( pos , " checked, " ) ;
if ( ! ( share - > state . changed & STATE_NOT_ANALYZED ) )
pos = strmov ( pos , " analyzed, " ) ;
if ( ! ( share - > state . changed & STATE_NOT_OPTIMIZED_KEYS ) )
pos = strmov ( pos , " optimized keys, " ) ;
if ( ! ( share - > state . changed & STATE_NOT_SORTED_PAGES ) )
pos = strmov ( pos , " sorted index pages, " ) ;
pos [ - 1 ] = 0 ; /* Remove extra ',' */
}
printf ( " Status: %s \n " , buff ) ;
if ( share - > base . auto_key )
{
2007-01-18 21:38:14 +02:00
printf ( " Auto increment key: %16d Last value: %18s \n " ,
2006-04-11 16:45:10 +03:00
share - > base . auto_key ,
llstr ( share - > state . auto_increment , llbuff ) ) ;
}
if ( share - > options & ( HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD ) )
2007-01-18 21:38:14 +02:00
printf ( " Checksum: %26s \n " , llstr ( info - > state - > checksum , llbuff ) ) ;
2006-04-11 16:45:10 +03:00
;
if ( share - > options & HA_OPTION_DELAY_KEY_WRITE )
printf ( " Keys are only flushed at close \n " ) ;
}
2007-01-18 21:38:14 +02:00
printf ( " Data records: %16s Deleted blocks: %18s \n " ,
2006-04-11 16:45:10 +03:00
llstr ( info - > state - > records , llbuff ) , llstr ( info - > state - > del , llbuff2 ) ) ;
if ( param - > testflag & T_SILENT )
DBUG_VOID_RETURN ; /* This is enough */
if ( param - > testflag & T_VERBOSE )
{
# ifdef USE_RELOC
2007-01-18 21:38:14 +02:00
printf ( " Init-relocation: %16s \n " , llstr ( share - > base . reloc , llbuff ) ) ;
2006-04-11 16:45:10 +03:00
# endif
2007-01-18 21:38:14 +02:00
printf ( " Datafile parts: %16s Deleted data: %18s \n " ,
2006-04-11 16:45:10 +03:00
llstr ( share - > state . split , llbuff ) ,
llstr ( info - > state - > empty , llbuff2 ) ) ;
2007-01-18 21:38:14 +02:00
printf ( " Datafile pointer (bytes): %11d Keyfile pointer (bytes): %13d \n " ,
2006-04-11 16:45:10 +03:00
share - > rec_reflength , share - > base . key_reflength ) ;
2007-01-18 21:38:14 +02:00
printf ( " Datafile length: %16s Keyfile length: %18s \n " ,
2006-04-11 16:45:10 +03:00
llstr ( info - > state - > data_file_length , llbuff ) ,
llstr ( info - > state - > key_file_length , llbuff2 ) ) ;
if ( info - > s - > base . reloc = = 1L & & info - > s - > base . records = = 1L )
puts ( " This is a one-record table " ) ;
else
{
if ( share - > base . max_data_file_length ! = HA_OFFSET_ERROR | |
share - > base . max_key_file_length ! = HA_OFFSET_ERROR )
2007-01-18 21:38:14 +02:00
printf ( " Max datafile length: %16s Max keyfile length: %18s \n " ,
2006-04-11 16:45:10 +03:00
llstr ( share - > base . max_data_file_length - 1 , llbuff ) ,
llstr ( share - > base . max_key_file_length - 1 , llbuff2 ) ) ;
}
}
2007-01-18 21:38:14 +02:00
printf ( " Block_size: %16d \n " , ( int ) share - > block_size ) ;
printf ( " Recordlength: %16d \n " , ( int ) share - > base . pack_reclength ) ;
2006-04-11 16:45:10 +03:00
if ( ! maria_is_all_keys_active ( share - > state . key_map , share - > base . keys ) )
{
longlong2str ( share - > state . key_map , buff , 2 ) ;
printf ( " Using only keys '%s' of %d possibly keys \n " ,
buff , share - > base . keys ) ;
}
puts ( " \n table description: " ) ;
printf ( " Key Start Len Index Type " ) ;
if ( param - > testflag & T_VERBOSE )
printf ( " Rec/key Root Blocksize " ) ;
VOID ( putchar ( ' \n ' ) ) ;
for ( key = keyseg_nr = 0 , keyinfo = & share - > keyinfo [ 0 ] ;
key < share - > base . keys ;
key + + , keyinfo + + )
{
keyseg = keyinfo - > seg ;
if ( keyinfo - > flag & HA_NOSAME ) text = " unique " ;
else if ( keyinfo - > flag & HA_FULLTEXT ) text = " fulltext " ;
else text = " multip. " ;
pos = buff ;
if ( keyseg - > flag & HA_REVERSE_SORT )
* pos + + = ' - ' ;
pos = strmov ( pos , type_names [ keyseg - > type ] ) ;
* pos + + = ' ' ;
* pos = 0 ;
if ( keyinfo - > flag & HA_PACK_KEY )
pos = strmov ( pos , prefix_packed_txt ) ;
if ( keyinfo - > flag & HA_BINARY_PACK_KEY )
pos = strmov ( pos , bin_packed_txt ) ;
if ( keyseg - > flag & HA_SPACE_PACK )
pos = strmov ( pos , diff_txt ) ;
if ( keyseg - > flag & HA_BLOB_PART )
pos = strmov ( pos , blob_txt ) ;
if ( keyseg - > flag & HA_NULL_PART )
pos = strmov ( pos , null_txt ) ;
* pos = 0 ;
printf ( " %-4d%-6ld%-3d %-8s%-21s " ,
key + 1 , ( long ) keyseg - > start + 1 , keyseg - > length , text , buff ) ;
if ( share - > state . key_root [ key ] ! = HA_OFFSET_ERROR )
llstr ( share - > state . key_root [ key ] , buff ) ;
else
buff [ 0 ] = 0 ;
if ( param - > testflag & T_VERBOSE )
printf ( " %11lu %12s %10d " ,
share - > state . rec_per_key_part [ keyseg_nr + + ] ,
buff , keyinfo - > block_length ) ;
VOID ( putchar ( ' \n ' ) ) ;
while ( ( + + keyseg ) - > type ! = HA_KEYTYPE_END )
{
pos = buff ;
if ( keyseg - > flag & HA_REVERSE_SORT )
* pos + + = ' - ' ;
pos = strmov ( pos , type_names [ keyseg - > type ] ) ;
* pos + + = ' ' ;
if ( keyseg - > flag & HA_SPACE_PACK )
pos = strmov ( pos , diff_txt ) ;
if ( keyseg - > flag & HA_BLOB_PART )
pos = strmov ( pos , blob_txt ) ;
if ( keyseg - > flag & HA_NULL_PART )
pos = strmov ( pos , null_txt ) ;
* pos = 0 ;
printf ( " %-6ld%-3d %-21s " ,
( long ) keyseg - > start + 1 , keyseg - > length , buff ) ;
if ( param - > testflag & T_VERBOSE )
printf ( " %11lu " , share - > state . rec_per_key_part [ keyseg_nr + + ] ) ;
VOID ( putchar ( ' \n ' ) ) ;
}
keyseg + + ;
}
if ( share - > state . header . uniques )
{
MARIA_UNIQUEDEF * uniqueinfo ;
puts ( " \n Unique Key Start Len Nullpos Nullbit Type " ) ;
for ( key = 0 , uniqueinfo = & share - > uniqueinfo [ 0 ] ;
key < share - > state . header . uniques ; key + + , uniqueinfo + + )
{
my_bool new_row = 0 ;
char null_bit [ 8 ] , null_pos [ 8 ] ;
printf ( " %-8d%-5d " , key + 1 , uniqueinfo - > key + 1 ) ;
for ( keyseg = uniqueinfo - > seg ; keyseg - > type ! = HA_KEYTYPE_END ; keyseg + + )
{
if ( new_row )
fputs ( " " , stdout ) ;
null_bit [ 0 ] = null_pos [ 0 ] = 0 ;
if ( keyseg - > null_bit )
{
sprintf ( null_bit , " %d " , keyseg - > null_bit ) ;
sprintf ( null_pos , " %ld " , ( long ) keyseg - > null_pos + 1 ) ;
}
printf ( " %-7ld%-5d%-9s%-10s%-30s \n " ,
( long ) keyseg - > start + 1 , keyseg - > length ,
null_pos , null_bit ,
type_names [ keyseg - > type ] ) ;
new_row = 1 ;
}
}
}
if ( param - > verbose > 1 )
{
char null_bit [ 8 ] , null_pos [ 8 ] ;
printf ( " \n Field Start Length Nullpos Nullbit Type " ) ;
if ( share - > options & HA_OPTION_COMPRESS_RECORD )
printf ( " Huff tree Bits " ) ;
VOID ( putchar ( ' \n ' ) ) ;
2007-01-18 21:38:14 +02:00
2006-04-11 16:45:10 +03:00
for ( field = 0 ; field < share - > base . fields ; field + + )
{
if ( share - > options & HA_OPTION_COMPRESS_RECORD )
2007-04-19 13:18:56 +03:00
type = share - > columndef [ field ] . base_type ;
2006-04-11 16:45:10 +03:00
else
2007-04-19 13:18:56 +03:00
type = ( enum en_fieldtype ) share - > columndef [ field ] . type ;
2006-04-11 16:45:10 +03:00
end = strmov ( buff , field_pack [ type ] ) ;
if ( share - > options & HA_OPTION_COMPRESS_RECORD )
{
2007-04-19 13:18:56 +03:00
if ( share - > columndef [ field ] . pack_type & PACK_TYPE_SELECTED )
2006-04-11 16:45:10 +03:00
end = strmov ( end , " , not_always " ) ;
2007-04-19 13:18:56 +03:00
if ( share - > columndef [ field ] . pack_type & PACK_TYPE_SPACE_FIELDS )
2006-04-11 16:45:10 +03:00
end = strmov ( end , " , no empty " ) ;
2007-04-19 13:18:56 +03:00
if ( share - > columndef [ field ] . pack_type & PACK_TYPE_ZERO_FILL )
2006-04-11 16:45:10 +03:00
{
2007-04-19 13:18:56 +03:00
sprintf ( end , " , zerofill(%d) " , share - > columndef [ field ] . space_length_bits ) ;
2006-04-11 16:45:10 +03:00
end = strend ( end ) ;
}
}
if ( buff [ 0 ] = = ' , ' )
strmov ( buff , buff + 2 ) ;
2007-04-19 13:18:56 +03:00
int10_to_str ( ( long ) share - > columndef [ field ] . length , length , 10 ) ;
2006-04-11 16:45:10 +03:00
null_bit [ 0 ] = null_pos [ 0 ] = 0 ;
2007-04-19 13:18:56 +03:00
if ( share - > columndef [ field ] . null_bit )
2006-04-11 16:45:10 +03:00
{
2007-04-19 13:18:56 +03:00
sprintf ( null_bit , " %d " , share - > columndef [ field ] . null_bit ) ;
sprintf ( null_pos , " %d " , share - > columndef [ field ] . null_pos + 1 ) ;
2006-04-11 16:45:10 +03:00
}
2007-01-18 21:38:14 +02:00
printf ( " %-6d%-6u%-7s%-8s%-8s%-35s " , field + 1 ,
2007-04-19 13:18:56 +03:00
( uint ) share - > columndef [ field ] . offset + 1 ,
2007-01-18 21:38:14 +02:00
length , null_pos , null_bit , buff ) ;
2006-04-11 16:45:10 +03:00
if ( share - > options & HA_OPTION_COMPRESS_RECORD )
{
2007-04-19 13:18:56 +03:00
if ( share - > columndef [ field ] . huff_tree )
2006-04-11 16:45:10 +03:00
printf ( " %3d %2d " ,
2007-04-19 13:18:56 +03:00
( uint ) ( share - > columndef [ field ] . huff_tree - share - > decode_trees ) + 1 ,
share - > columndef [ field ] . huff_tree - > quick_table_bits ) ;
2006-04-11 16:45:10 +03:00
}
VOID ( putchar ( ' \n ' ) ) ;
}
}
DBUG_VOID_RETURN ;
} /* describe */
/* Sort records according to one key */
static int maria_sort_records ( HA_CHECK * param ,
2007-07-02 20:45:15 +03:00
register MARIA_HA * info , char * name ,
2006-04-11 16:45:10 +03:00
uint sort_key ,
my_bool write_info ,
my_bool update_index )
{
int got_error ;
uint key ;
MARIA_KEYDEF * keyinfo ;
File new_file ;
2007-07-02 20:45:15 +03:00
uchar * temp_buff ;
2006-04-11 16:45:10 +03:00
ha_rows old_record_count ;
MARIA_SHARE * share = info - > s ;
char llbuff [ 22 ] , llbuff2 [ 22 ] ;
MARIA_SORT_INFO sort_info ;
MARIA_SORT_PARAM sort_param ;
DBUG_ENTER ( " sort_records " ) ;
bzero ( ( char * ) & sort_info , sizeof ( sort_info ) ) ;
bzero ( ( char * ) & sort_param , sizeof ( sort_param ) ) ;
sort_param . sort_info = & sort_info ;
sort_info . param = param ;
keyinfo = & share - > keyinfo [ sort_key ] ;
got_error = 1 ;
temp_buff = 0 ;
new_file = - 1 ;
if ( ! maria_is_key_active ( share - > state . key_map , sort_key ) )
{
_ma_check_print_warning ( param ,
" Can't sort table '%s' on key %d; No such key " ,
name , sort_key + 1 ) ;
param - > error_printed = 0 ;
DBUG_RETURN ( 0 ) ; /* Nothing to do */
}
if ( keyinfo - > flag & HA_FULLTEXT )
{
_ma_check_print_warning ( param , " Can't sort table '%s' on FULLTEXT key %d " ,
name , sort_key + 1 ) ;
param - > error_printed = 0 ;
DBUG_RETURN ( 0 ) ; /* Nothing to do */
}
if ( share - > data_file_type = = COMPRESSED_RECORD )
{
_ma_check_print_warning ( param , " Can't sort read-only table '%s' " , name ) ;
param - > error_printed = 0 ;
DBUG_RETURN ( 0 ) ; /* Nothing to do */
}
if ( ! ( param - > testflag & T_SILENT ) )
{
printf ( " - Sorting records for MARIA-table '%s' \n " , name ) ;
if ( write_info )
printf ( " Data records: %9s Deleted: %9s \n " ,
llstr ( info - > state - > records , llbuff ) ,
llstr ( info - > state - > del , llbuff2 ) ) ;
}
if ( share - > state . key_root [ sort_key ] = = HA_OFFSET_ERROR )
DBUG_RETURN ( 0 ) ; /* Nothing to do */
if ( init_io_cache ( & info - > rec_cache , - 1 , ( uint ) param - > write_buffer_length ,
WRITE_CACHE , share - > pack . header_length , 1 ,
MYF ( MY_WME | MY_WAIT_IF_FULL ) ) )
goto err ;
info - > opt_flag | = WRITE_CACHE_USED ;
2007-07-02 20:45:15 +03:00
if ( ! ( temp_buff = ( uchar * ) my_alloca ( ( uint ) keyinfo - > block_length ) ) )
2006-04-11 16:45:10 +03:00
{
_ma_check_print_error ( param , " Not enough memory for key block " ) ;
goto err ;
}
2007-07-02 20:45:15 +03:00
if ( ! ( sort_param . record = ( uchar * ) my_malloc ( ( uint ) share - > base . pack_reclength ,
2006-04-11 16:45:10 +03:00
MYF ( 0 ) ) ) )
{
_ma_check_print_error ( param , " Not enough memory for record " ) ;
goto err ;
}
fn_format ( param - > temp_filename , name , " " , MARIA_NAME_DEXT , 2 + 4 + 32 ) ;
2007-01-18 21:38:14 +02:00
new_file = my_create ( fn_format ( param - > temp_filename ,
param - > temp_filename , " " ,
2007-04-19 13:18:56 +03:00
DATA_TMP_EXT ,
MY_REPLACE_EXT | MY_UNPACK_FILENAME ) ,
0 , param - > tmpfile_createflag ,
2007-01-18 21:38:14 +02:00
MYF ( 0 ) ) ;
2006-04-11 16:45:10 +03:00
if ( new_file < 0 )
{
_ma_check_print_error ( param , " Can't create new tempfile: '%s' " ,
param - > temp_filename ) ;
goto err ;
}
if ( share - > pack . header_length )
2007-04-04 23:37:09 +03:00
if ( maria_filecopy ( param , new_file , info - > dfile . file , 0L ,
share - > pack . header_length ,
" datafile-header " ) )
2006-04-11 16:45:10 +03:00
goto err ;
info - > rec_cache . file = new_file ; /* Use this file for cacheing*/
maria_lock_memory ( param ) ;
for ( key = 0 ; key < share - > base . keys ; key + + )
share - > keyinfo [ key ] . flag | = HA_SORT_ALLOWS_SAME ;
2007-04-04 23:37:09 +03:00
if ( my_pread ( share - > kfile . file , temp_buff ,
2006-04-11 16:45:10 +03:00
( uint ) keyinfo - > block_length ,
share - > state . key_root [ sort_key ] ,
MYF ( MY_NABP + MY_WME ) ) )
{
_ma_check_print_error ( param , " Can't read indexpage from filepos: %s " ,
( ulong ) share - > state . key_root [ sort_key ] ) ;
goto err ;
}
/* Setup param for _ma_sort_write_record */
sort_info . info = info ;
sort_info . new_data_file_type = share - > data_file_type ;
sort_param . fix_datafile = 1 ;
sort_param . master = 1 ;
sort_param . filepos = share - > pack . header_length ;
old_record_count = info - > state - > records ;
info - > state - > records = 0 ;
if ( sort_info . new_data_file_type ! = COMPRESSED_RECORD )
info - > state - > checksum = 0 ;
2007-01-18 21:38:14 +02:00
if ( sort_record_index ( & sort_param , info , keyinfo ,
share - > state . key_root [ sort_key ] ,
2006-04-11 16:45:10 +03:00
temp_buff , sort_key , new_file , update_index ) | |
maria_write_data_suffix ( & sort_info , 1 ) | |
flush_io_cache ( & info - > rec_cache ) )
goto err ;
if ( info - > state - > records ! = old_record_count )
{
_ma_check_print_error ( param , " found %s of %s records " ,
llstr ( info - > state - > records , llbuff ) ,
llstr ( old_record_count , llbuff2 ) ) ;
goto err ;
}
2007-04-04 23:37:09 +03:00
VOID ( my_close ( info - > dfile . file , MYF ( MY_WME ) ) ) ;
2006-04-11 16:45:10 +03:00
param - > out_flag | = O_NEW_DATA ; /* Data in new file */
2007-04-04 23:37:09 +03:00
info - > dfile . file = new_file ; /* Use new datafile */
2006-04-11 16:45:10 +03:00
info - > state - > del = 0 ;
info - > state - > empty = 0 ;
share - > state . dellink = HA_OFFSET_ERROR ;
info - > state - > data_file_length = sort_param . filepos ;
share - > state . split = info - > state - > records ; /* Only hole records */
share - > state . version = ( ulong ) time ( ( time_t * ) 0 ) ;
info - > update = ( short ) ( HA_STATE_CHANGED | HA_STATE_ROW_CHANGED ) ;
if ( param - > testflag & T_WRITE_LOOP )
{
VOID ( fputs ( " \r " , stdout ) ) ; VOID ( fflush ( stdout ) ) ;
}
got_error = 0 ;
err :
if ( got_error & & new_file > = 0 )
{
VOID ( end_io_cache ( & info - > rec_cache ) ) ;
( void ) my_close ( new_file , MYF ( MY_WME ) ) ;
2007-01-18 21:38:14 +02:00
( void ) my_delete ( param - > temp_filename , MYF ( MY_WME ) ) ;
2006-04-11 16:45:10 +03:00
}
if ( temp_buff )
{
2007-07-02 20:45:15 +03:00
my_afree ( ( uchar * ) temp_buff ) ;
2006-04-11 16:45:10 +03:00
}
my_free ( sort_param . record , MYF ( MY_ALLOW_ZERO_PTR ) ) ;
info - > opt_flag & = ~ ( READ_CACHE_USED | WRITE_CACHE_USED ) ;
VOID ( end_io_cache ( & info - > rec_cache ) ) ;
my_free ( sort_info . buff , MYF ( MY_ALLOW_ZERO_PTR ) ) ;
sort_info . buff = 0 ;
share - > state . sortkey = sort_key ;
- speed optimization:
minimize writes to transactional Maria tables: don't write
data pages, state, and open_count at the end of each statement.
Data pages will be written by a background thread periodically.
State will be written by Checkpoint periodically.
open_count serves to detect when a table is potentially damaged
due to an unclean mysqld stop, but thanks to recovery an unclean
mysqld stop will be corrected and so open_count becomes useless.
As state is written less often, it is often obsolete on disk,
we thus should avoid to read it from disk.
- by removing the data page writes above, it is necessary to put
it back at the start of some statements like check, repair and
delete_all. It was already necessary in fact (see ma_delete_all.c).
- disabling CACHE INDEX on Maria tables for now (fixes crash
of test 'key_cache' when run with --default-storage-engine=maria).
- correcting some fishy code in maria_extra.c (we possibly could lose
index pages when doing a DROP TABLE under Windows, in theory).
storage/maria/ha_maria.cc:
disable CACHE INDEX in Maria for now (there is a single cache for now),
it crashes and it's not a priority
storage/maria/ma_bitmap.c:
debug message
storage/maria/ma_check.c:
The statement before maria_repair() may not flush state,
so it needs to be done by maria_repair() (indeed this function
uses maria_open(HA_OPEN_COPY) so reads state from disk,
so needs to find it up-to-date on disk).
For safety (but normally this is not needed) we remove index blocks
out of the cache before repairing.
_ma_flush_blocks() becomes _ma_flush_table_files_after_repair():
it now additionally flushes the data file and state and syncs files.
As a side effect, the assertion "no WRITE_CACHE_USED" from
_ma_flush_table_files() fired so we move all end_io_cache() done
at the end of repair to before the calls to _ma_flush_table_files_after_repair().
storage/maria/ma_close.c:
when closing a transactional table, we fsync it. But we need to
do this only after writing its state.
We need to write the state at close time only for transactional
tables (the other tables do that at last unlock).
Putting back the O_RDONLY||crashed condition which I had
removed earlier.
Unmap the file before syncing it (does not matter now as Maria
does not use mmap)
storage/maria/ma_delete_all.c:
need to flush data pages before chsize-ing it. Was needed even when
we flushed data pages at the end of each statement, because we didn't
anyway do it if under LOCK TABLES: the change here thus fixes this bug:
create table t(a int) engine=maria;lock tables t write;
insert into t values(1);delete from t;unlock tables;check table t;
"Size of datafile is: 16384 Should be: 8192"
(an obsolete page went to disk after the chsize(), at unlock time).
storage/maria/ma_extra.c:
When doing share->last_version=0, we make the MARIA_SHARE-in-memory
invisible to future openers, so need to have an up-to-date state
on disk for them. The same way, future openers will reopen the data
and index file, so they will not find our cached blocks, so we
need to flush them to disk.
In HA_EXTRA_FORCE_REOPEN, this probably happens naturally as all
tables normally get closed, we however add a safety flush.
In HA_EXTRA_PREPARE_FOR_RENAME, we need to do the flushing. On
Windows we additionally need to close files.
In HA_EXTRA_PREPARE_FOR_DROP, we don't need to flush anything but
remove dirty cached blocks from memory. On Windows we need to close
files.
Closing files forces us to sync them before (requirement for transactional
tables).
For mutex reasons (don't lock intern_lock twice), we move
maria_lock_database() and _ma_decrement_open_count() first in the list
of operations.
Flush also data file in HA_EXTRA_FLUSH.
storage/maria/ma_locking.c:
For transactional tables:
- don't write data pages / state at unlock time;
as a consequence, "share->changed=0" cannot be done.
- don't write state in _ma_writeinfo()
- don't maintain open_count on disk (Recovery corrects the table in case of crash
anyway, and we gain speed by not writing open_count to disk),
For non-transactional tables, flush the state at unlock only
if the table was changed (optimization).
Code which read the state from disk is relevant only with
external locking, we disable it (if want to re-enable it, it shouldn't
for transactional tables as state on disk may be obsolete (such tables
does not flush state at unlock anymore).
The comment "We have to flush the write cache" is now wrong because
maria_lock_database(F_UNLCK) now happens before thr_unlock(), and
we are not using external locking.
storage/maria/ma_open.c:
_ma_state_info_read() is only used in ma_open.c, making it static
storage/maria/ma_recovery.c:
set MARIA_SHARE::changed to TRUE when we are going to apply a
REDO/UNDO, so that the state gets flushed at close.
storage/maria/ma_test_recovery.expected:
Changes introduced by this patch:
- good: the "open" (table open, not properly closed) is gone,
it was pointless for a recovered table
- bad: stemming from different moments of writing the index's state
probably (_ma_writeinfo() used to write the state after every row
write in ma_test* programs, doesn't anymore as the table is
transactional): some differences in indexes (not relevant as we don't
yet have recovery for them); some differences in count of records
(changed from a wrong value to another wrong value) (not relevant
as we don't recover this count correctly yet anyway, though
a patch will be pushed soon).
storage/maria/ma_test_recovery:
for repeatable output, no names of varying directories.
storage/maria/maria_chk.c:
function renamed
storage/maria/maria_def.h:
Function became local to ma_open.c. Function renamed.
2007-09-06 16:53:26 +02:00
DBUG_RETURN ( _ma_flush_table_files_after_repair ( param , info ) | got_error ) ;
2006-04-11 16:45:10 +03:00
} /* sort_records */
2007-01-18 21:38:14 +02:00
/* Sort records recursive using one index */
2006-04-11 16:45:10 +03:00
static int sort_record_index ( MARIA_SORT_PARAM * sort_param , MARIA_HA * info ,
MARIA_KEYDEF * keyinfo ,
2007-07-02 20:45:15 +03:00
my_off_t page , uchar * buff , uint sort_key ,
2006-04-11 16:45:10 +03:00
File new_file , my_bool update_index )
{
uint nod_flag , used_length , key_length ;
2007-07-02 20:45:15 +03:00
uchar * temp_buff , * keypos , * endpos ;
2006-04-11 16:45:10 +03:00
my_off_t next_page , rec_pos ;
2007-07-02 20:45:15 +03:00
uchar lastkey [ HA_MAX_KEY_BUFF ] ;
2006-04-11 16:45:10 +03:00
char llbuff [ 22 ] ;
MARIA_SORT_INFO * sort_info = sort_param - > sort_info ;
HA_CHECK * param = sort_info - > param ;
DBUG_ENTER ( " sort_record_index " ) ;
nod_flag = _ma_test_if_nod ( buff ) ;
temp_buff = 0 ;
if ( nod_flag )
{
2007-07-02 20:45:15 +03:00
if ( ! ( temp_buff = ( uchar * ) my_alloca ( ( uint ) keyinfo - > block_length ) ) )
2006-04-11 16:45:10 +03:00
{
_ma_check_print_error ( param , " Not Enough memory " ) ;
DBUG_RETURN ( - 1 ) ;
}
}
2007-06-09 14:52:17 +03:00
used_length = maria_data_on_page ( buff ) ;
2006-04-11 16:45:10 +03:00
keypos = buff + 2 + nod_flag ;
endpos = buff + used_length ;
for ( ; ; )
{
_sanity ( __FILE__ , __LINE__ ) ;
if ( nod_flag )
{
2007-01-18 21:38:14 +02:00
next_page = _ma_kpos ( nod_flag , keypos ) ;
2007-07-02 20:45:15 +03:00
if ( my_pread ( info - > s - > kfile . file , ( uchar * ) temp_buff ,
2006-04-11 16:45:10 +03:00
( uint ) keyinfo - > block_length , next_page ,
MYF ( MY_NABP + MY_WME ) ) )
{
_ma_check_print_error ( param , " Can't read keys from filepos: %s " ,
llstr ( next_page , llbuff ) ) ;
goto err ;
}
2007-01-18 21:38:14 +02:00
if ( sort_record_index ( sort_param , info , keyinfo , next_page , temp_buff ,
sort_key ,
2006-04-11 16:45:10 +03:00
new_file , update_index ) )
goto err ;
}
_sanity ( __FILE__ , __LINE__ ) ;
if ( keypos > = endpos | |
( key_length = ( * keyinfo - > get_key ) ( keyinfo , nod_flag , & keypos , lastkey ) )
= = 0 )
break ;
rec_pos = _ma_dpos ( info , 0 , lastkey + key_length ) ;
2007-01-18 21:38:14 +02:00
if ( ( * info - > s - > read_record ) ( info , sort_param - > record , rec_pos ) )
2006-04-11 16:45:10 +03:00
{
_ma_check_print_error ( param , " %d when reading datafile " , my_errno ) ;
goto err ;
}
if ( rec_pos ! = sort_param - > filepos & & update_index )
{
_ma_dpointer ( info , keypos - nod_flag - info - > s - > rec_reflength ,
sort_param - > filepos ) ;
if ( maria_movepoint ( info , sort_param - > record , rec_pos , sort_param - > filepos ,
sort_key ) )
{
_ma_check_print_error ( param , " %d when updating key-pointers " , my_errno ) ;
goto err ;
}
}
if ( _ma_sort_write_record ( sort_param ) )
goto err ;
}
/* Clear end of block to get better compression if the table is backuped */
2007-07-02 20:45:15 +03:00
bzero ( ( uchar * ) buff + used_length , keyinfo - > block_length - used_length ) ;
if ( my_pwrite ( info - > s - > kfile . file , ( uchar * ) buff , ( uint ) keyinfo - > block_length ,
2006-04-11 16:45:10 +03:00
page , param - > myf_rw ) )
{
_ma_check_print_error ( param , " %d when updating keyblock " , my_errno ) ;
goto err ;
}
if ( temp_buff )
2007-07-02 20:45:15 +03:00
my_afree ( ( uchar * ) temp_buff ) ;
2006-04-11 16:45:10 +03:00
DBUG_RETURN ( 0 ) ;
err :
if ( temp_buff )
2007-07-02 20:45:15 +03:00
my_afree ( ( uchar * ) temp_buff ) ;
2006-04-11 16:45:10 +03:00
DBUG_RETURN ( 1 ) ;
} /* sort_record_index */
2007-10-03 18:10:32 +02:00
# include "ma_check_standalone.h"