1 /* Copyright (C) 2006-2003 MySQL AB
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 /* Describe, check and repair of MARIA tables */
17
18 #include "ma_fulltext.h"
19 #include <myisamchk.h>
20 #include <my_bit.h>
21 #include <m_ctype.h>
22 #include <my_getopt.h>
23 #include <my_check_opt.h>
24 #include <my_handler_errors.h>
25 /* Remove next line if you want aria_chk to produce a stack trace */
26 #undef HAVE_BACKTRACE
27 #include <my_stacktrace.h>
28
29 static uint decode_bits;
30 static char **default_argv;
31 static const char *load_default_groups[]= { "aria_chk", 0 };
32 static const char *set_collation_name, *opt_tmpdir, *opt_log_dir;
33 static const char *default_log_dir;
34 static CHARSET_INFO *set_collation;
35 static int stopwords_inited= 0;
36 static MY_TMPDIR maria_chk_tmpdir;
37 static my_bool opt_transaction_logging, opt_debug;
38 static my_bool opt_ignore_control_file, opt_require_control_file;
39 static my_bool opt_warning_for_wrong_transid, opt_update_state;
40 static my_bool have_control_file= 0;
41
42 static const char *type_names[]=
43 {
44 "impossible","char","binary", "short", "long", "float",
45 "double","number","unsigned short",
46 "unsigned long","longlong","ulonglong","int24",
47 "uint24","int8","varchar", "varbin", "varchar2", "varbin2", "bit",
48 "?","?"
49 };
50
51 static const char *prefix_packed_txt="packed ",
52 *bin_packed_txt="prefix ",
53 *diff_txt="stripped ",
54 *null_txt="NULL",
55 *blob_txt="BLOB ";
56
57 static const char *field_pack[]=
58 {
59 "","no endspace", "no prespace",
60 "no zeros", "blob", "constant", "table-lockup",
61 "always zero","varchar","unique-hash","?","?"
62 };
63
64 static const char *record_formats[]=
65 {
66 "Fixed length", "Packed", "Compressed", "Block", "No data", "?", "?"
67 };
68
69 static const char *bitmap_description[]=
70 {
71 "Empty page", "Part filled head page","Part filled head page",
72 "Part filled head page", "Full head page",
73 "Part filled tail page","Part filled tail page",
74 "Full tail or blob page"
75 };
76
77 static const char *maria_stats_method_str="nulls_unequal";
78 static char default_open_errmsg[]= "%d when opening Aria table '%s'";
79 static char default_close_errmsg[]= "%d when closing Aria table '%s'";
80
81 static void get_options(int *argc,char * * *argv);
82 static void print_version(void);
83 static void usage(void);
84 static int maria_chk(HA_CHECK *param, char *filename);
85 static void descript(HA_CHECK *param, register MARIA_HA *info, char *name);
86 static int maria_sort_records(HA_CHECK *param, register MARIA_HA *info,
87 char *name, uint sort_key,
88 my_bool write_info, my_bool update_index);
89 static int sort_record_index(MARIA_SORT_PARAM *sort_param, MARIA_PAGE *page,
90 uint sortkey, File new_file,
91 my_bool update_index);
92 static my_bool write_log_record(HA_CHECK *param);
93 ATTRIBUTE_NORETURN static void my_exit(int exit_code);
94
95 HA_CHECK check_param;
96
97 /*
98 Register handler error messages for usage with my_error()
99
100 NOTES
101 This is safe to call multiple times as my_error_register()
102 will ignore calls to register already registered error numbers.
103 */
104
get_handler_error_messages(int e)105 static const char **get_handler_error_messages(int e __attribute__((unused)))
106 {
107 return handler_error_messages;
108 }
109
110
111 /* Free memory and exit */
112
my_exit(int exit_code)113 static void my_exit(int exit_code)
114 {
115 free_tmpdir(&maria_chk_tmpdir);
116 free_defaults(default_argv);
117 my_error_unregister(HA_ERR_FIRST,
118 HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
119 my_end(check_param.testflag & T_INFO ?
120 MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
121 exit(exit_code);
122 }
123
124 /* Main program */
125
main(int argc,char ** argv)126 int main(int argc, char **argv)
127 {
128 int error;
129 MY_INIT(argv[0]);
130
131 my_setup_stacktrace();
132 default_log_dir= opt_log_dir= maria_data_root= ".";
133 maria_chk_init(&check_param);
134 check_param.opt_lock_memory= 1; /* Lock memory if possible */
135 check_param.using_global_keycache = 0;
136 get_options(&argc,(char***) &argv);
137 maria_quick_table_bits=decode_bits;
138 error=0;
139 maria_init();
140 my_error_register(get_handler_error_messages, HA_ERR_FIRST,
141 HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
142
143 maria_block_size= 0; /* Use block size from control file */
144 if (!opt_ignore_control_file)
145 {
146 if ((ma_control_file_open(FALSE, opt_require_control_file ||
147 !(check_param.testflag & T_SILENT),
148 TRUE)))
149 {
150 if (opt_require_control_file ||
151 (opt_transaction_logging && (check_param.testflag & T_REP_ANY)))
152 {
153 error= 1;
154 goto end;
155 }
156 }
157 else
158 have_control_file= 1;
159 }
160 if (!have_control_file)
161 opt_warning_for_wrong_transid= 0;
162
163 /*
164 If we are doing a repair, user may want to store this repair into the log
165 so that the log has a complete history and can be used to replay.
166 */
167 if (opt_transaction_logging && (check_param.testflag & T_REP_ANY))
168 {
169 if (init_pagecache(maria_log_pagecache,
170 TRANSLOG_PAGECACHE_SIZE, 0, 0,
171 TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0 ||
172 translog_init(opt_log_dir, TRANSLOG_FILE_SIZE,
173 0, 0, maria_log_pagecache,
174 TRANSLOG_DEFAULT_FLAGS, 0))
175 {
176 _ma_check_print_error(&check_param,
177 "Can't initialize transaction logging. Run "
178 "recovery with switch --skip-transaction-log");
179 error= 1;
180 goto end;
181 }
182 }
183
184 while (--argc >= 0)
185 {
186 int new_error=maria_chk(&check_param, *(argv++));
187 if ((check_param.testflag & T_REP_ANY) != T_REP)
188 check_param.testflag&= ~T_REP;
189 fflush(stdout);
190 fflush(stderr);
191 if (check_param.wrong_trd_printed &&
192 (check_param.testflag & T_FORCE_CREATE) &&
193 !(check_param.error_printed | check_param.warning_printed))
194 {
195 /* Only wrong create_trd. Run zerofill */
196 ulonglong old_testflag= check_param.testflag;
197 check_param.testflag= T_ZEROFILL;
198 error|= maria_chk(&check_param, argv[-1]);
199 check_param.testflag= old_testflag;
200 check_param.error_printed= 0;
201 check_param.warning_printed= 0;
202 fflush(stdout);
203 fflush(stderr);
204 }
205 if ((check_param.error_printed | check_param.warning_printed) &&
206 (check_param.testflag & T_FORCE_CREATE) &&
207 (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
208 T_SORT_INDEX))))
209 {
210 ulonglong old_testflag=check_param.testflag;
211 if (!(check_param.testflag & T_REP))
212 check_param.testflag|= T_REP_BY_SORT;
213 check_param.testflag&= ~T_EXTEND; /* Not needed */
214 error|=maria_chk(&check_param, argv[-1]);
215 check_param.testflag= old_testflag;
216 fflush(stdout);
217 fflush(stderr);
218 }
219 error|=new_error;
220 if (argc && (!(check_param.testflag & T_SILENT) ||
221 check_param.testflag & T_INFO))
222 {
223 puts("\n---------\n");
224 fflush(stdout);
225 }
226 }
227 end:
228 if (check_param.total_files > 1)
229 { /* Only if descript */
230 char buff[22],buff2[22];
231 if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
232 puts("\n---------");
233 printf("\nTotal of all %d Aria-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
234 llstr(check_param.total_deleted,buff2));
235 }
236 maria_end();
237 my_exit(error);
238 #ifndef _lint
239 return 0; /* No compiler warning */
240 #endif
241 } /* main */
242
243 enum options_mc {
244 OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
245 OPT_CORRECT_CHECKSUM, OPT_CREATE_MISSING_KEYS, OPT_PAGE_BUFFER_SIZE,
246 OPT_KEY_CACHE_BLOCK_SIZE, OPT_MARIA_BLOCK_SIZE,
247 OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
248 OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
249 OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
250 OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG,
251 OPT_ZEROFILL_KEEP_LSN,
252 OPT_REQUIRE_CONTROL_FILE, OPT_IGNORE_CONTROL_FILE,
253 OPT_LOG_DIR, OPT_WARNING_FOR_WRONG_TRANSID
254 };
255
256 static struct my_option my_long_options[] =
257 {
258 {"analyze", 'a',
259 "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
260 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
261 #ifdef __NETWARE__
262 {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
263 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
264 #endif
265 {"block-search", 'b',
266 "No help available.",
267 0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
268 {"backup", 'B',
269 "Make a backup of the .MAD file as 'filename-time.BAK'.",
270 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
271 {"character-sets-dir", OPT_CHARSETS_DIR,
272 "Directory where character sets are.",
273 (char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
274 {"check", 'c',
275 "Check table for errors.",
276 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
277 {"check-only-changed", 'C',
278 "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).",
279 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
280 {"correct-checksum", OPT_CORRECT_CHECKSUM,
281 "Correct checksum information for table.",
282 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
283 {"create-missing-keys", OPT_CREATE_MISSING_KEYS,
284 "Create missing keys. This assumes that the data file is correct and that "
285 "the the number of rows stored in the index file is correct. Enables "
286 "--quick",
287 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
288 #ifndef DBUG_OFF
289 {"debug", '#',
290 "Output debug log. Often this is 'd:t:o,filename'.",
291 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
292 #endif
293 {"description", 'd',
294 "Prints some information about table.",
295 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
296 {"data-file-length", 'D',
297 "Max length of data file (when recreating data-file when it's full).",
298 &check_param.max_data_file_length,
299 &check_param.max_data_file_length,
300 0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
301 {"extend-check", 'e',
302 "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.",
303 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
304 {"fast", 'F',
305 "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).",
306 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
307 {"force", 'f',
308 "Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
309 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
310 {"HELP", 'H',
311 "Print all argument options sorted alphabetically and exit.",
312 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
313 {"help", '?',
314 "Print all options by groups and exit. See also --HELP",
315 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
316 {"information", 'i',
317 "Print statistics information about table that is checked.",
318 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
319 { "ignore-control-file", OPT_IGNORE_CONTROL_FILE,
320 "Ignore the control file",
321 (uchar**)&opt_ignore_control_file, 0, 0, GET_BOOL, NO_ARG,
322 0, 0, 0, 0, 0, 0},
323 {"keys-used", 'k',
324 "Tell Aria to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
325 &check_param.keys_in_use,
326 &check_param.keys_in_use,
327 0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
328 {"datadir", 'h',
329 "Path for control file (and logs if --logdir not used).",
330 (char**) &maria_data_root, 0, 0, GET_STR, REQUIRED_ARG,
331 0, 0, 0, 0, 0, 0},
332 {"logdir", OPT_LOG_DIR,
333 "Path for log files.",
334 (char**) &opt_log_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
335 {"max-record-length", OPT_MAX_RECORD_LENGTH,
336 "Skip rows bigger than this if aria_chk can't allocate memory to hold it",
337 &check_param.max_record_length,
338 &check_param.max_record_length,
339 0, GET_ULL, REQUIRED_ARG, LONGLONG_MAX, 0, LONGLONG_MAX, 0, 0, 0},
340 {"medium-check", 'm',
341 "Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
342 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
343 {"quick", 'q', "Faster repair by not modifying the data file.",
344 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
345 {"read-only", 'T',
346 "Don't mark table as checked.",
347 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
348 {"recover", 'r',
349 "Can fix almost anything except unique keys that aren't unique.",
350 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
351 {"parallel-recover", 'p',
352 "Same as '-r' but creates all the keys in parallel.",
353 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
354 {"safe-recover", 'o',
355 "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.",
356 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
357 {"sort-recover", 'n',
358 "Force recovering with sorting even if the temporary file was very big.",
359 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
360 { "require-control-file", OPT_REQUIRE_CONTROL_FILE,
361 "Abort if cannot find control file",
362 (uchar**)&opt_require_control_file, 0, 0, GET_BOOL, NO_ARG,
363 0, 0, 0, 0, 0, 0},
364 #ifdef DEBUG
365 {"start-check-pos", OPT_START_CHECK_POS,
366 "No help available.",
367 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
368 #endif
369 {"set-auto-increment", 'A',
370 "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.",
371 &check_param.auto_increment_value,
372 &check_param.auto_increment_value,
373 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
374 {"set-collation", OPT_SET_COLLATION,
375 "Change the collation used by the index",
376 (char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG,
377 0, 0, 0, 0, 0, 0},
378 {"silent", 's',
379 "Only print errors. One can use two -s to make aria_chk very silent.",
380 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
381 {"sort-index", 'S',
382 "Sort index blocks. This speeds up 'read-next' in applications.",
383 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
384 {"sort-records", 'R',
385 "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!)",
386 &check_param.opt_sort_key,
387 &check_param.opt_sort_key,
388 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
389 {"tmpdir", 't', "Path for temporary files.", (char**) &opt_tmpdir,
390 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
391 {"transaction-log", OPT_TRANSACTION_LOG,
392 "Log repair command to transaction log",
393 &opt_transaction_logging, &opt_transaction_logging,
394 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
395 {"update-state", 'U',
396 "Mark tables as crashed if any errors were found and clean if check "
397 "didn't find any errors but table was marked as 'not clean' before. This "
398 "allows one to get rid of warnings like 'table not properly closed'. "
399 "If table was updated, update also the timestamp for when check was made. "
400 "This option is on by default!",
401 &opt_update_state, &opt_update_state, 0, GET_BOOL, NO_ARG,
402 1, 0, 0, 0, 0, 0},
403 {"unpack", 'u',
404 "Unpack file packed with aria_pack.",
405 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
406 {"verbose", 'v',
407 "Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
408 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
409 {"version", 'V', "Print version and exit.",
410 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
411 {"wait", 'w', "Wait if table is locked.",
412 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
413 {"warning-for-wrong-transaction-id", OPT_WARNING_FOR_WRONG_TRANSID,
414 "Give a warning if we find a transaction id in the table that is bigger"
415 "than what exists in the control file. Use --skip-... to disable warning",
416 &opt_warning_for_wrong_transid, &opt_warning_for_wrong_transid,
417 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
418 { "page_buffer_size", OPT_PAGE_BUFFER_SIZE,
419 "Size of page buffer. Used by --safe-repair",
420 &check_param.use_buffers, &check_param.use_buffers, 0,
421 GET_ULONG, REQUIRED_ARG, PAGE_BUFFER_INIT, 1024L*1024L,
422 SIZE_T_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
423 { "read_buffer_size", OPT_READ_BUFFER_SIZE,
424 "Read buffer size for sequential reads during scanning",
425 &check_param.read_buffer_length,
426 &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
427 (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
428 ~0ULL, (long) MALLOC_OVERHEAD, (long) 1L, 0},
429 { "write_buffer_size", OPT_WRITE_BUFFER_SIZE,
430 "Write buffer size for sequential writes during repair of fixed size or dynamic size rows",
431 &check_param.write_buffer_length,
432 &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
433 (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
434 ~0UL, (long) MALLOC_OVERHEAD, (long) 1L, 0},
435 { "sort_buffer_size", OPT_SORT_BUFFER_SIZE,
436 "Size of sort buffer. Used by --recover",
437 &check_param.orig_sort_buffer_length,
438 &check_param.orig_sort_buffer_length, 0, GET_ULL, REQUIRED_ARG,
439 SORT_BUFFER_INIT, MIN_SORT_BUFFER, SIZE_T_MAX, MALLOC_OVERHEAD, 1L, 0},
440 { "sort_key_blocks", OPT_SORT_KEY_BLOCKS,
441 "Internal buffer for sorting keys; Don't touch :)",
442 &check_param.sort_key_blocks,
443 &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
444 BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
445 { "decode_bits", OPT_DECODE_BITS, "", &decode_bits,
446 &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
447 { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "", &ft_min_word_len,
448 &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN,
449 0, 1, 0},
450 { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", &ft_max_word_len,
451 &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10,
452 HA_FT_MAXCHARLEN, 0, 1, 0},
453 { "aria_ft_stopword_file", OPT_FT_STOPWORD_FILE,
454 "Use stopwords from this file instead of built-in list.",
455 (char**) &ft_stopword_file, (char**) &ft_stopword_file, 0, GET_STR,
456 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
457 { "stats_method", OPT_STATS_METHOD,
458 "Specifies how index statistics collection code should treat NULLs. "
459 "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
460 "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
461 (char**) &maria_stats_method_str, (char**) &maria_stats_method_str, 0,
462 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
463 { "zerofill", 'z',
464 "Fill empty space in data and index files with zeroes. This makes the data file movable between different servers. It also fixes any wrong transaction or LSN numbers in the table after a crash or if someone removed the Aria log files.",
465 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
466 { "zerofill-keep-lsn", OPT_ZEROFILL_KEEP_LSN,
467 "Like --zerofill but does not zero out LSN of data/index pages;"
468 " used only for testing and debugging",
469 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
470 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
471 };
472
473
print_version(void)474 static void print_version(void)
475 {
476 printf("%s Ver 1.3 for %s on %s\n", my_progname, SYSTEM_TYPE,
477 MACHINE_TYPE);
478 }
479
480
usage(void)481 static void usage(void)
482 {
483 print_version();
484 puts("By Monty, for your professional use");
485 puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
486 puts("Description, check and repair of Aria tables.");
487 puts("Used without options all tables on the command will be checked for errors");
488 printf("Usage: %s [OPTIONS] tables[.MAI]\n", my_progname_short);
489 printf("\nGlobal options:\n");
490 #ifndef DBUG_OFF
491 printf("\
492 -#, --debug=... Output debug log. Often this is 'd:t:o,filename'.\n");
493 #endif
494 printf("\
495 -H, --HELP Print all argument options sorted alphabetically.\n\
496 -?, --help Print all options by groups\n\
497 --datadir=path Path for control file (and logs if --logdir not used)\n\
498 --logdir=path Path for log files\n\
499 --ignore-control-file Don't open the control file. Only use this if you\n\
500 are sure the tables are not in use by another\n\
501 program!\n\
502 --require-control-file Abort if we can't find/read the aria_log_control\n\
503 file\n\
504 -s, --silent Only print errors. One can use two -s to make\n\
505 maria_chk very silent.\n\
506 -t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
507 specified, separated by ");
508 #if defined( __WIN__) || defined(__NETWARE__)
509 printf("semicolon (;)");
510 #else
511 printf("colon (:)");
512 #endif
513 printf(", they will be used\n\
514 in a round-robin fashion.\n\
515 -v, --verbose Print more information. This can be used with\n\
516 --description and --check. Use many -v for more verbosity.\n\
517 -V, --version Print version and exit.\n\
518 -w, --wait Wait if table is locked.\n\n");
519 #ifdef DEBUG
520 puts(" --start-check-pos=# Start reading file at given offset.\n");
521 #endif
522
523 puts("Check options (check is the default action for aria_chk):\n\
524 -c, --check Check table for errors.\n\
525 -e, --extend-check Check the table VERY throughly. Only use this in\n\
526 extreme cases as aria_chk should normally be able to\n\
527 find out if the table is ok even without this switch.\n\
528 -F, --fast Check only tables that haven't been closed properly.\n\
529 -C, --check-only-changed\n\
530 Check only tables that have changed since last check.\n\
531 -f, --force Restart with '-r' if there are any errors in the table.\n\
532 States will be updated as with '--update-state'.\n\
533 -i, --information Print statistics information about table that is checked.\n\
534 -m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
535 all errors. Should be good enough for most cases.\n\
536 -T, --read-only Don't mark table as checked.\n\
537 -U, --update-state Mark tables as crashed if any errors were found and\n\
538 clean if check didn't find any errors but table was\n\
539 marked as 'not clean' before. This allows one to get\n\
540 rid of warnings like 'table not properly closed'. If\n\
541 table was updated, update also the timestamp for when\n\
542 the check was made. This option is on by default!\n\
543 Use --skip-update-state to disable.\n\
544 --warning-for-wrong-transaction-id\n\
545 Give a warning if we find a transaction id in the table that is bigger\n\
546 than what exists in the control file. Use --skip-... to disable warning\n\
547 ");
548
549 puts("\
550 Recover (repair)/ options (When using '--recover' or '--safe-recover'):\n\
551 -B, --backup Make a backup of the .MAD file as 'filename-time.BAK'.\n\
552 --correct-checksum Correct checksum information for table.\n\
553 -D, --data-file-length=# Max length of data file (when recreating data\n\
554 file when it's full).\n\
555 --create-missing-keys\n\
556 Create missing keys. This assumes that the data\n\
557 file is correct and that the the number of rows stored\n\
558 in the index file is correct. Enables --quick.\n\
559 -e, --extend-check Try to recover every possible row from the data file\n\
560 Normally this will also find a lot of garbage rows;\n\
561 Don't use this option if you are not totally desperate.\n\
562 -f, --force Overwrite old temporary files. Add another --force to\n\
563 avoid 'sort_buffer_size is too small' errors.\n\
564 In this case we will attempt to do the repair with the\n\
565 given sort_buffer_size and dynamically allocate\n\
566 as many management buffers as needed.\n\
567 -k, --keys-used=# Tell Aria to update only some specific keys. # is a\n\
568 bit mask of which keys to use. This can be used to\n\
569 get faster inserts.\n\
570 --max-record-length=#\n\
571 Skip rows bigger than this if aria_chk can't allocate\n\
572 memory to hold it.\n\
573 -r, --recover Can fix almost anything except unique keys that aren't\n\
574 unique.\n\
575 -n, --sort-recover Forces recovering with sorting even if the temporary\n\
576 file would be very big.\n\
577 -p, --parallel-recover\n\
578 Uses the same technique as '-r' and '-n', but creates\n\
579 all the keys in parallel, in different threads.");
580 puts("\
581 -o, --safe-recover Uses old recovery method; Slower than '-r' but can\n \
582 handle a couple of cases where '-r' reports that it\n\
583 can't fix the data file.\n\
584 --transaction-log Log repair command to transaction log. This is needed\n\
585 if one wants to use the aria_read_log to repeat the \n\
586 repair\n\
587 --character-sets-dir=...\n\
588 Directory where character sets are.\n\
589 --set-collation=name\n\
590 Change the collation used by the index.\n\
591 -q, --quick Faster repair by not modifying the data file.\n\
592 One can give a second '-q' to force aria_chk to\n\
593 modify the original datafile in case of duplicate keys.\n\
594 NOTE: Tables where the data file is corrupted can't be\n\
595 fixed with this option.\n\
596 -u, --unpack Unpack file packed with ariapack.\n\
597 ");
598
599 puts("Other actions:\n\
600 -a, --analyze Analyze distribution of keys. Will make some joins in\n\
601 MariaDB faster. You can check the calculated distribution\n\
602 by using '--description --verbose table_name'.\n\
603 --stats_method=name Specifies how index statistics collection code should\n\
604 treat NULLs. Possible values of name are \"nulls_unequal\"\n\
605 (default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
606 \"nulls_ignored\".\n\
607 -d, --description Prints some information about table.\n\
608 -A, --set-auto-increment[=value]\n\
609 Force auto_increment to start at this or higher value\n\
610 If no value is given, then sets the next auto_increment\n\
611 value to the highest used value for the auto key + 1.\n\
612 -S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
613 applications.\n\
614 -R, --sort-records=#\n\
615 Sort records according to an index. This makes your\n\
616 data much more localized and may speed up things\n\
617 (It may be VERY slow to do a sort the first time!).\n\
618 -b, --block-search=#\n\
619 Find a record, a block at given offset belongs to.\n\
620 -z, --zerofill Fill empty space in data and index files with zeroes.\n\
621 This makes the data file movable between different \n\
622 servers. It also fixes any wrong transaction or LSN\n\
623 numbers in the table after a crash or if someone\n\
624 removed the Aria log files.\n\
625 --zerofill-keep-lsn Like --zerofill but does not zero out LSN of\n\
626 data/index pages.");
627
628 puts("Variables:\n\
629 --page_buffer_size=# Size of page buffer. Used by --safe-repair\n\
630 --read_buffer_size=# Read buffer size for sequential reads during scanning\n\
631 --sort_buffer_size=# Size of sort buffer. Used by --recover\n\
632 --sort_key_blocks=# Internal buffer for sorting keys; Don't touch :)\n\
633 --write_buffer_size=# Write buffer size for sequential writes during repair");
634
635 print_defaults("my", load_default_groups);
636 my_print_variables(my_long_options);
637 }
638
639 const char *maria_stats_method_names[] = {"nulls_unequal", "nulls_equal",
640 "nulls_ignored", NullS};
641 TYPELIB maria_stats_method_typelib= {
642 array_elements(maria_stats_method_names) - 1, "",
643 maria_stats_method_names, NULL};
644
645 /* Read options */
646
647 static my_bool
get_one_option(const struct my_option * opt,const char * argument,const char * filename)648 get_one_option(const struct my_option *opt,
649 const char *argument,
650 const char *filename __attribute__((unused)))
651 {
652 switch (opt->id) {
653 #ifdef __NETWARE__
654 case OPT_AUTO_CLOSE:
655 setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
656 break;
657 #endif
658 case 'a':
659 if (argument == disabled_my_option)
660 check_param.testflag&= ~T_STATISTICS;
661 else
662 check_param.testflag|= T_STATISTICS;
663 break;
664 case 'A':
665 if (argument)
666 check_param.auto_increment_value= strtoull(argument, NULL, 0);
667 else
668 check_param.auto_increment_value= 0; /* Set to max used value */
669 check_param.testflag|= T_AUTO_INC;
670 break;
671 case 'b':
672 check_param.search_after_block= strtoul(argument, NULL, 10);
673 break;
674 case 'B':
675 if (argument == disabled_my_option)
676 check_param.testflag&= ~T_BACKUP_DATA;
677 else
678 check_param.testflag|= T_BACKUP_DATA;
679 break;
680 case 'c':
681 if (argument == disabled_my_option)
682 check_param.testflag&= ~T_CHECK;
683 else
684 check_param.testflag|= T_CHECK;
685 break;
686 case 'C':
687 if (argument == disabled_my_option)
688 check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
689 else
690 check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
691 break;
692 case 'D':
693 check_param.max_data_file_length=strtoll(argument, NULL, 10);
694 break;
695 case 's': /* silent */
696 if (argument == disabled_my_option)
697 check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
698 else
699 {
700 if (check_param.testflag & T_SILENT)
701 check_param.testflag|= T_VERY_SILENT;
702 check_param.testflag|= T_SILENT;
703 check_param.testflag&= ~T_WRITE_LOOP;
704 }
705 break;
706 case 'w':
707 if (argument == disabled_my_option)
708 check_param.testflag&= ~T_WAIT_FOREVER;
709 else
710 check_param.testflag|= T_WAIT_FOREVER;
711 break;
712 case 'd': /* description if isam-file */
713 if (argument == disabled_my_option)
714 check_param.testflag&= ~T_DESCRIPT;
715 else
716 check_param.testflag|= T_DESCRIPT;
717 break;
718 case 'e': /* extend check */
719 if (argument == disabled_my_option)
720 check_param.testflag&= ~T_EXTEND;
721 else
722 check_param.testflag|= T_EXTEND;
723 break;
724 case 'i':
725 if (argument == disabled_my_option)
726 check_param.testflag&= ~T_INFO;
727 else
728 check_param.testflag|= T_INFO;
729 break;
730 case 'f':
731 if (argument == disabled_my_option)
732 {
733 check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
734 check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE |
735 T_FORCE_SORT_MEMORY);
736 }
737 else
738 {
739 if (check_param.testflag & T_FORCE_CREATE)
740 check_param.testflag= T_FORCE_SORT_MEMORY;
741 check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
742 check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
743 }
744 break;
745 case 'F':
746 if (argument == disabled_my_option)
747 check_param.testflag&= ~T_FAST;
748 else
749 check_param.testflag|= T_FAST;
750 break;
751 case 'k':
752 check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
753 break;
754 case 'm':
755 if (argument == disabled_my_option)
756 check_param.testflag&= ~T_MEDIUM;
757 else
758 check_param.testflag|= T_MEDIUM; /* Medium check */
759 break;
760 case 'r': /* Repair table */
761 check_param.testflag&= ~T_REP_ANY;
762 if (argument != disabled_my_option)
763 check_param.testflag|= T_REP_BY_SORT;
764 break;
765 case 'p':
766 check_param.testflag&= ~T_REP_ANY;
767 if (argument != disabled_my_option)
768 check_param.testflag|= T_REP_PARALLEL;
769 break;
770 case 'o':
771 check_param.testflag&= ~T_REP_ANY;
772 check_param.force_sort= 0;
773 if (argument != disabled_my_option)
774 {
775 check_param.testflag|= T_REP;
776 my_disable_async_io= 1; /* More safety */
777 }
778 break;
779 case 'n':
780 check_param.testflag&= ~T_REP_ANY;
781 if (argument == disabled_my_option)
782 check_param.force_sort= 0;
783 else
784 {
785 check_param.testflag|= T_REP_BY_SORT;
786 check_param.force_sort= 1;
787 }
788 break;
789 case 'q':
790 if (argument == disabled_my_option)
791 check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
792 else
793 {
794 /*
795 If T_QUICK was specified before, but not OPT_CREATE_MISSING_KEYS,
796 then add T_FORCE_UNIQUENESS.
797 */
798 check_param.testflag|=
799 ((check_param.testflag & (T_QUICK | T_CREATE_MISSING_KEYS)) ==
800 T_QUICK ? T_FORCE_UNIQUENESS : T_QUICK);
801 }
802 break;
803 case OPT_CREATE_MISSING_KEYS:
804 if (argument == disabled_my_option)
805 check_param.testflag&= ~(T_QUICK | T_CREATE_MISSING_KEYS);
806 else
807 {
808 check_param.testflag|= T_QUICK | T_CREATE_MISSING_KEYS;
809 /* Use repair by sort by default */
810 if (!(check_param.testflag & T_REP_ANY))
811 check_param.testflag|= T_REP_BY_SORT;
812 }
813 break;
814 case 'u':
815 if (argument == disabled_my_option)
816 check_param.testflag&= ~T_UNPACK;
817 else
818 {
819 check_param.testflag|= T_UNPACK;
820 if (!(check_param.testflag & T_REP_ANY))
821 check_param.testflag|= T_REP_BY_SORT;
822 }
823 break;
824 case 'v': /* Verbose */
825 if (argument == disabled_my_option)
826 {
827 check_param.testflag&= ~T_VERBOSE;
828 check_param.verbose=0;
829 }
830 else
831 {
832 check_param.testflag|= T_VERBOSE;
833 check_param.verbose++;
834 }
835 break;
836 case 'R': /* Sort records */
837 if (argument == disabled_my_option)
838 check_param.testflag&= ~T_SORT_RECORDS;
839 else
840 {
841 check_param.testflag|= T_SORT_RECORDS;
842 check_param.opt_sort_key= (uint) atoi(argument) - 1;
843 if (check_param.opt_sort_key >= MARIA_MAX_KEY)
844 {
845 fprintf(stderr,
846 "The value of the sort key is bigger than max key: %d.\n",
847 MARIA_MAX_KEY);
848 my_exit(1);
849 }
850 }
851 break;
852 case 'S': /* Sort index */
853 if (argument == disabled_my_option)
854 check_param.testflag&= ~T_SORT_INDEX;
855 else
856 check_param.testflag|= T_SORT_INDEX;
857 break;
858 case 'T':
859 if (argument == disabled_my_option)
860 check_param.testflag&= ~T_READONLY;
861 else
862 check_param.testflag|= T_READONLY;
863 break;
864 case 'U':
865 if (argument == disabled_my_option)
866 check_param.testflag&= ~T_UPDATE_STATE;
867 else
868 check_param.testflag|= T_UPDATE_STATE;
869 break;
870 case '#':
871 DBUG_SET_INITIAL(argument ? argument : "d:t:o,/tmp/aria_chk.trace");
872 opt_debug= 1;
873 break;
874 case 'V':
875 print_version();
876 my_exit(0);
877 case OPT_CORRECT_CHECKSUM:
878 if (argument == disabled_my_option)
879 check_param.testflag&= ~T_CALC_CHECKSUM;
880 else
881 check_param.testflag|= T_CALC_CHECKSUM;
882 break;
883 case OPT_STATS_METHOD:
884 {
885 int method;
886 enum_handler_stats_method UNINIT_VAR(method_conv);
887 maria_stats_method_str= argument;
888 if ((method=find_type(argument, &maria_stats_method_typelib, 2)) <= 0)
889 {
890 fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
891 my_exit(1);
892 }
893 switch (method-1) {
894 case 0:
895 method_conv= MI_STATS_METHOD_NULLS_EQUAL;
896 break;
897 case 1:
898 method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
899 break;
900 case 2:
901 method_conv= MI_STATS_METHOD_IGNORE_NULLS;
902 break;
903 default: abort(); /* Impossible */
904 }
905 check_param.stats_method= method_conv;
906 break;
907 }
908 #ifdef DEBUG /* Only useful if debugging */
909 case OPT_START_CHECK_POS:
910 check_param.start_check_pos= strtoull(argument, NULL, 0);
911 break;
912 #endif
913 case 'z':
914 if (argument == disabled_my_option)
915 check_param.testflag&= ~T_ZEROFILL;
916 else
917 check_param.testflag|= T_ZEROFILL;
918 break;
919 case OPT_ZEROFILL_KEEP_LSN:
920 if (argument == disabled_my_option)
921 check_param.testflag&= ~(T_ZEROFILL_KEEP_LSN | T_ZEROFILL);
922 else
923 check_param.testflag|= (T_ZEROFILL_KEEP_LSN | T_ZEROFILL);
924 break;
925 case 'H':
926 my_print_help(my_long_options);
927 my_print_variables(my_long_options);
928 my_exit(0);
929 case '?':
930 usage();
931 my_exit(0);
932 }
933 return 0;
934 }
935
936
get_options(register int * argc,register char *** argv)937 static void get_options(register int *argc,register char ***argv)
938 {
939 int ho_error;
940
941 load_defaults_or_exit("my", load_default_groups, argc, argv);
942 default_argv= *argv;
943 check_param.testflag= T_UPDATE_STATE;
944 if (isatty(fileno(stdout)))
945 check_param.testflag|=T_WRITE_LOOP;
946
947 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
948 my_exit(ho_error);
949
950 /* If using repair, then update checksum if one uses --update-state */
951 if ((check_param.testflag & T_UPDATE_STATE) &&
952 (check_param.testflag & T_REP_ANY))
953 check_param.testflag|= T_CALC_CHECKSUM;
954
955 if (*argc == 0)
956 {
957 usage();
958 my_exit(-1);
959 }
960
961 if ((check_param.testflag & T_UNPACK) &&
962 (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
963 {
964 fprintf(stderr, "%s: --unpack can't be used with --quick or --sort-records\n",
965 my_progname_short);
966 my_exit(1);
967 }
968 if ((check_param.testflag & T_READONLY) &&
969 (check_param.testflag &
970 (T_REP_ANY | T_STATISTICS | T_AUTO_INC |
971 T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
972 {
973 fprintf(stderr, "%s: Can't use --readonly when repairing or sorting\n",
974 my_progname_short);
975 my_exit(1);
976 }
977
978 if (!opt_debug)
979 {
980 DEBUGGER_OFF; /* Speed up things a bit */
981 }
982 if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir))
983 my_exit(1);
984
985 check_param.tmpdir=&maria_chk_tmpdir;
986
987 if (set_collation_name)
988 if (!(set_collation= get_charset_by_name(set_collation_name,
989 MYF(MY_WME))))
990 my_exit(1);
991
992 if (maria_data_root != default_log_dir && opt_log_dir == default_log_dir)
993 {
994 /* --datadir was used and --log-dir was not. Set log-dir to datadir */
995 opt_log_dir= maria_data_root;
996 }
997
998 /* If we are using zerofill, then we don't need to read the control file */
999 if ((check_param.testflag & (T_ZEROFILL_KEEP_LSN | T_ZEROFILL)) &&
1000 !(check_param.testflag & ~(T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX | T_STATISTICS | T_CHECK | T_FAST | T_CHECK_ONLY_CHANGED)))
1001 opt_ignore_control_file= 1;
1002
1003 return;
1004 } /* get options */
1005
1006
1007 /**
1008 Check/repair table
1009
1010 @return 0 table is ok
1011 @return 1 Got warning during check
1012 @return 2 Got error during check/repair.
1013 */
1014
maria_chk(HA_CHECK * param,char * filename)1015 static int maria_chk(HA_CHECK *param, char *filename)
1016 {
1017 int error,lock_type,recreate;
1018 uint warning_printed_by_chk_status;
1019 my_bool rep_quick= MY_TEST(param->testflag & (T_QUICK | T_FORCE_UNIQUENESS));
1020 my_bool born_transactional;
1021 MARIA_HA *info;
1022 File datafile;
1023 char llbuff[22],llbuff2[22];
1024 my_bool state_updated=0;
1025 MARIA_SHARE *share;
1026 DBUG_ENTER("maria_chk");
1027
1028 param->out_flag= error= param->error_printed= recreate= 0;
1029 param->warning_printed= param->wrong_trd_printed= 0;
1030 datafile=0;
1031 param->isam_file_name=filename; /* For error messages */
1032 warning_printed_by_chk_status= 0;
1033 if (!(info=maria_open(filename,
1034 (param->testflag & (T_DESCRIPT | T_READONLY)) ?
1035 O_RDONLY : O_RDWR,
1036 HA_OPEN_FOR_REPAIR |
1037 ((param->testflag & T_WAIT_FOREVER) ?
1038 HA_OPEN_WAIT_IF_LOCKED :
1039 (param->testflag & T_DESCRIPT) ?
1040 HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED),
1041 0)))
1042 {
1043 /* Avoid twice printing of isam file name */
1044 param->error_printed++;
1045 switch (my_errno) {
1046 case HA_ERR_CRASHED:
1047 _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);
1048 break;
1049 case HA_ERR_NOT_A_TABLE:
1050 _ma_check_print_error(param,"'%s' is not a Aria table",filename);
1051 break;
1052 case HA_ERR_CRASHED_ON_USAGE:
1053 _ma_check_print_error(param,"'%s' is marked as crashed",filename);
1054 break;
1055 case HA_ERR_CRASHED_ON_REPAIR:
1056 _ma_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
1057 break;
1058 case HA_ERR_OLD_FILE:
1059 _ma_check_print_error(param,"'%s' is a old type of Aria table", filename);
1060 break;
1061 case HA_ERR_NEW_FILE:
1062 _ma_check_print_error(param,"'%s' uses new features not supported by this version of the Aria library", filename);
1063 break;
1064 case HA_ERR_END_OF_FILE:
1065 _ma_check_print_error(param,"Couldn't read complete header from '%s'", filename);
1066 break;
1067 case EAGAIN:
1068 _ma_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
1069 break;
1070 case ENOENT:
1071 _ma_check_print_error(param,"File '%s' doesn't exist",filename);
1072 break;
1073 case EACCES:
1074 _ma_check_print_error(param,"You don't have permission to use '%s'",
1075 filename);
1076 break;
1077 default:
1078 _ma_check_print_error(param,"%d when opening Aria table '%s'",
1079 my_errno,filename);
1080 break;
1081 }
1082 DBUG_RETURN(1);
1083 }
1084 share= info->s;
1085 share->tot_locks-= share->r_locks;
1086 share->r_locks=0;
1087 maria_block_size= share->base.block_size;
1088
1089 if (share->data_file_type == BLOCK_RECORD ||
1090 ((param->testflag & T_UNPACK) &&
1091 share->state.header.org_data_file_type == BLOCK_RECORD))
1092 {
1093 if (param->testflag & T_SORT_RECORDS)
1094 {
1095 _ma_check_print_error(param,
1096 "Record format used by '%s' is is not yet supported with sort-records",
1097 filename);
1098 param->error_printed= 0;
1099 error= 1;
1100 goto end2;
1101 }
1102 /* We can't do parallel repair with BLOCK_RECORD yet */
1103 if (param->testflag & T_REP_PARALLEL)
1104 {
1105 param->testflag&= ~T_REP_PARALLEL;
1106 param->testflag|= T_REP_BY_SORT;
1107 }
1108 }
1109 if ((share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED) &&
1110 !(param->testflag & T_DESCRIPT))
1111 {
1112 _ma_check_print_warning(param,
1113 "Table %s is encrypted. Only --description (-d) "
1114 "option is supported", filename);
1115 param->warning_printed= 0;
1116 goto end2;
1117 }
1118
1119 /*
1120 Skip the checking of the file if:
1121 We are using --fast and the table is closed properly
1122 We are using --check-only-changed-tables and the table hasn't changed
1123 */
1124 if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
1125 {
1126 my_bool need_to_check= (maria_is_crashed(info) ||
1127 share->state.open_count != 0);
1128
1129 if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
1130 ((share->state.changed & (STATE_CHANGED | STATE_CRASHED_FLAGS |
1131 STATE_IN_REPAIR) ||
1132 !(param->testflag & T_CHECK_ONLY_CHANGED))))
1133 need_to_check=1;
1134
1135 if (info->s->base.keys && info->state->records)
1136 {
1137 if ((param->testflag & T_STATISTICS) &&
1138 (share->state.changed & STATE_NOT_ANALYZED))
1139 need_to_check=1;
1140 if ((param->testflag & T_SORT_INDEX) &&
1141 (share->state.changed & STATE_NOT_SORTED_PAGES))
1142 need_to_check=1;
1143 if ((param->testflag & T_REP_BY_SORT) &&
1144 (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1145 need_to_check=1;
1146 }
1147 if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
1148 (share->state.changed & (STATE_CHANGED | STATE_CRASHED_FLAGS |
1149 STATE_IN_REPAIR)))
1150 need_to_check=1;
1151 if (!need_to_check)
1152 {
1153 if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1154 printf("Aria file: %s is already checked\n",filename);
1155 if (maria_close(info))
1156 {
1157 _ma_check_print_error(param,"%d when closing Aria table '%s'",
1158 my_errno,filename);
1159 DBUG_RETURN(1);
1160 }
1161 DBUG_RETURN(0);
1162 }
1163 }
1164 if ((param->testflag & (T_REP_ANY | T_STATISTICS |
1165 T_SORT_RECORDS | T_SORT_INDEX)) &&
1166 (((param->testflag & T_UNPACK) &&
1167 share->data_file_type == COMPRESSED_RECORD) ||
1168 mi_uint2korr(share->state.header.state_info_length) !=
1169 MARIA_STATE_INFO_SIZE ||
1170 mi_uint2korr(share->state.header.base_info_length) !=
1171 MARIA_BASE_INFO_SIZE ||
1172 maria_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
1173 ~share->state.key_map) ||
1174 maria_test_if_almost_full(info) ||
1175 info->s->state.header.file_version[3] != maria_file_magic[3] ||
1176 (set_collation &&
1177 set_collation->number != share->base.language)))
1178 {
1179 if (set_collation)
1180 param->language= set_collation->number;
1181 if (maria_recreate_table(param, &info,filename))
1182 {
1183 fprintf(stderr, "Aria table '%s' is not fixed because of errors\n",
1184 filename);
1185 DBUG_RETURN(-1);
1186 }
1187 recreate=1;
1188 if (!(param->testflag & T_REP_ANY))
1189 {
1190 param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
1191 if (!(param->testflag & T_SILENT))
1192 printf("- '%s' has old table-format. Recreating index\n",filename);
1193 rep_quick= 1;
1194 }
1195 share= info->s;
1196 share->tot_locks-= share->r_locks;
1197 share->r_locks=0;
1198 }
1199
1200 if (param->testflag & T_DESCRIPT)
1201 {
1202 param->total_files++;
1203 param->total_records+=info->state->records;
1204 param->total_deleted+=info->state->del;
1205 descript(param, info, filename);
1206 maria_close(info); /* Should always succeed */
1207 DBUG_RETURN(0);
1208 }
1209
1210 if (!stopwords_inited++)
1211 ft_init_stopwords();
1212
1213 if (!(param->testflag & T_READONLY))
1214 lock_type = F_WRLCK; /* table is changed */
1215 else
1216 lock_type= F_RDLCK;
1217 if (info->lock_type == F_RDLCK)
1218 info->lock_type=F_UNLCK; /* Read only table */
1219 if (_ma_readinfo(info,lock_type,0))
1220 {
1221 _ma_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
1222 filename,my_errno);
1223 param->error_printed=0;
1224 error= 1;
1225 goto end2;
1226 }
1227 /*
1228 _ma_readinfo() has locked the table.
1229 We mark the table as locked (without doing file locks) to be able to
1230 use functions that only works on locked tables (like row caching).
1231 */
1232 maria_lock_database(info, F_EXTRA_LCK);
1233 datafile= info->dfile.file;
1234 if (init_pagecache(maria_pagecache, (size_t) param->use_buffers, 0, 0,
1235 maria_block_size, 0, MY_WME) == 0)
1236 {
1237 _ma_check_print_error(param, "Can't initialize page cache with %lu memory",
1238 (ulong) param->use_buffers);
1239 error= 1;
1240 goto end2;
1241 }
1242
1243 if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1244 T_ZEROFILL))
1245 {
1246 /*
1247 Mark table as not transactional to avoid logging. Should not be needed,
1248 maria_repair and maria_zerofill do it already.
1249 */
1250 _ma_tmp_disable_logging_for_table(info, FALSE);
1251
1252 if (param->testflag & T_REP_ANY)
1253 {
1254 ulonglong tmp=share->state.key_map;
1255 maria_copy_keys_active(share->state.key_map, share->base.keys,
1256 param->keys_in_use);
1257 if (tmp != share->state.key_map)
1258 info->update|=HA_STATE_CHANGED;
1259
1260 if (rep_quick &&
1261 maria_chk_del(param, info, param->testflag & ~T_VERBOSE))
1262 {
1263 if (param->testflag & T_FORCE_CREATE)
1264 {
1265 rep_quick=0;
1266 _ma_check_print_info(param,"Creating new data file\n");
1267 }
1268 else
1269 {
1270 error=1;
1271 _ma_check_print_error(param,
1272 "Quick-recover aborted; Run recovery without switch 'q'");
1273 }
1274 }
1275 }
1276 if (!error)
1277 {
1278 /*
1279 Unless this was only --zerofill-keep-lsn, old REDOs are not
1280 applicable, tell the server's Recovery to ignore them; we don't
1281 know what the log's end LSN is now, so we just let the server know
1282 that it will have to find and store it.
1283 This is the only case where create_rename_lsn can be a horizon and not
1284 a LSN.
1285 If this was only --zerofill-keep-lsn, the table can be used in
1286 Recovery and especially in this scenario: do a dirty-copy-based backup
1287 (snapshot-like), --zerofill-keep-lsn on the copies to achieve better
1288 compression, compress the copies with an external tool, and after a
1289 restore, Recovery still works (because pages and state still have
1290 their correct LSNs).
1291 */
1292 if (share->base.born_transactional &&
1293 ((param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1294 T_ZEROFILL | T_ZEROFILL_KEEP_LSN)) !=
1295 (T_ZEROFILL | T_ZEROFILL_KEEP_LSN)))
1296 {
1297 share->state.create_rename_lsn= share->state.is_of_horizon=
1298 share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
1299 share->state.create_trid= 0;
1300 }
1301 }
1302 if (!error && (param->testflag & T_REP_ANY))
1303 {
1304 if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
1305 (maria_is_any_key_active(share->state.key_map) ||
1306 (rep_quick && !param->keys_in_use && !recreate)) &&
1307 maria_test_if_sort_rep(info, info->state->records,
1308 info->s->state.key_map,
1309 param->force_sort))
1310 {
1311 if (param->testflag & T_REP_BY_SORT)
1312 error=maria_repair_by_sort(param,info,filename,rep_quick);
1313 else
1314 error=maria_repair_parallel(param,info,filename,rep_quick);
1315 state_updated=1;
1316 }
1317 else
1318 error=maria_repair(param, info,filename,rep_quick);
1319 }
1320 if (!error && (param->testflag & T_SORT_RECORDS))
1321 {
1322 /*
1323 The data file is nowadays reopened in the repair code so we should
1324 soon remove the following reopen-code
1325 */
1326 #ifndef TO_BE_REMOVED
1327 if (param->out_flag & O_NEW_DATA)
1328 { /* Change temp file to org file */
1329 mysql_file_close(info->dfile.file, MYF(MY_WME)); /* Close new file */
1330 error|=maria_change_to_newfile(filename,MARIA_NAME_DEXT,DATA_TMP_EXT,
1331 0, MYF(0));
1332 if (_ma_open_datafile(info, info->s))
1333 error=1;
1334 param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
1335 param->read_cache.file= info->dfile.file;
1336 }
1337 #endif
1338 if (! error)
1339 {
1340 uint key;
1341 /*
1342 We can't update the index in maria_sort_records if we have a
1343 prefix compressed or fulltext index
1344 */
1345 my_bool update_index=1;
1346 for (key=0 ; key < share->base.keys; key++)
1347 if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY|HA_FULLTEXT))
1348 update_index=0;
1349
1350 error=maria_sort_records(param,info,filename,param->opt_sort_key,
1351 /* what is the following parameter for ? */
1352 (my_bool) !(param->testflag & T_REP),
1353 update_index);
1354 datafile= info->dfile.file; /* This is now locked */
1355 if (!error && !update_index)
1356 {
1357 if (param->verbose)
1358 puts("Table had a compressed index; We must now recreate the index");
1359 error=maria_repair_by_sort(param,info,filename,1);
1360 }
1361 }
1362 }
1363 if (!error && (param->testflag & T_SORT_INDEX))
1364 error= maria_sort_index(param,info,filename);
1365 if (!error && (param->testflag & T_ZEROFILL))
1366 error= maria_zerofill(param, info, filename);
1367 if (!error)
1368 {
1369 DBUG_PRINT("info", ("Resetting crashed state"));
1370 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS |
1371 STATE_IN_REPAIR);
1372 }
1373 else
1374 maria_mark_crashed(info);
1375 }
1376 else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1377 {
1378 if (!(param->testflag & T_VERY_SILENT) || param->testflag & T_INFO)
1379 printf("Checking Aria file: %s\n",filename);
1380 if (!(param->testflag & T_SILENT))
1381 printf("Data records: %7s Deleted blocks: %7s\n",
1382 llstr(info->state->records,llbuff),
1383 llstr(info->state->del,llbuff2));
1384 maria_chk_init_for_check(param, info);
1385 if (opt_warning_for_wrong_transid == 0)
1386 param->max_trid= ~ (ulonglong) 0;
1387
1388 error= maria_chk_status(param,info);
1389 /* Forget warning printed by maria_chk_status if no problems found */
1390 warning_printed_by_chk_status= param->warning_printed;
1391 param->warning_printed= 0;
1392
1393 maria_intersect_keys_active(share->state.key_map, param->keys_in_use);
1394 error|= maria_chk_size(param,info);
1395 if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1396 error|=maria_chk_del(param, info,param->testflag);
1397 if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1398 !param->start_check_pos)))
1399 {
1400 error|=maria_chk_key(param, info);
1401 if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1402 error=maria_update_state_info(param, info,
1403 ((param->testflag & T_STATISTICS) ?
1404 UPDATE_STAT : 0) |
1405 ((param->testflag & T_AUTO_INC) ?
1406 UPDATE_AUTO_INC : 0));
1407 }
1408 if ((!rep_quick && !error) ||
1409 !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1410 {
1411 init_io_cache(¶m->read_cache,datafile,
1412 (uint) param->read_buffer_length,
1413 READ_CACHE,
1414 (param->start_check_pos ?
1415 param->start_check_pos :
1416 share->pack.header_length),
1417 1,
1418 MYF(MY_WME));
1419 maria_lock_memory(param);
1420 if ((info->s->data_file_type != STATIC_RECORD) ||
1421 (param->testflag & (T_EXTEND | T_MEDIUM)))
1422 error|=maria_chk_data_link(param, info,
1423 MY_TEST(param->testflag & T_EXTEND));
1424 end_io_cache(¶m->read_cache);
1425 }
1426 if (!error)
1427 {
1428 if (((share->state.changed &
1429 (STATE_CHANGED | STATE_CRASHED_FLAGS | STATE_IN_REPAIR)) ||
1430 share->state.open_count != 0)
1431 && (param->testflag & T_UPDATE_STATE))
1432 info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1433 DBUG_PRINT("info", ("Resetting crashed state"));
1434 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS |
1435 STATE_IN_REPAIR);
1436 }
1437 else if (!maria_is_crashed(info) &&
1438 (param->testflag & T_UPDATE_STATE))
1439 { /* Mark crashed */
1440 maria_mark_crashed(info);
1441 info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1442 }
1443 }
1444
1445 if ((param->testflag & T_AUTO_INC) ||
1446 ((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1447 _ma_update_auto_increment_key(param, info,
1448 (my_bool)
1449 !MY_TEST(param->testflag & T_AUTO_INC));
1450
1451 if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1452 {
1453 error|=maria_update_state_info(param, info,
1454 UPDATE_OPEN_COUNT |
1455 (((param->testflag &
1456 (T_REP_ANY | T_UPDATE_STATE)) ?
1457 UPDATE_TIME : 0) |
1458 (state_updated ? UPDATE_STAT : 0) |
1459 ((param->testflag & T_SORT_RECORDS) ?
1460 UPDATE_SORT : 0)));
1461 if (warning_printed_by_chk_status)
1462 _ma_check_print_info(param, "Aria table '%s' was ok. Status updated",
1463 filename);
1464 else if (!(param->testflag & T_SILENT))
1465 printf("State updated\n");
1466 warning_printed_by_chk_status= 0;
1467 }
1468 info->update&= ~HA_STATE_CHANGED;
1469 _ma_reenable_logging_for_table(info, FALSE);
1470 maria_lock_database(info, F_UNLCK);
1471
1472 end2:
1473 born_transactional= share->base.born_transactional;
1474 if (maria_close(info))
1475 {
1476 _ma_check_print_error(param, default_close_errmsg, my_errno, filename);
1477 DBUG_RETURN(1);
1478 }
1479 end_pagecache(maria_pagecache, 1);
1480 if (error == 0)
1481 {
1482 if (param->out_flag & O_NEW_DATA)
1483 error|=maria_change_to_newfile(filename,MARIA_NAME_DEXT,DATA_TMP_EXT,
1484 param->backup_time,
1485 ((param->testflag & T_BACKUP_DATA) ?
1486 MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1487 }
1488 if (opt_transaction_logging &&
1489 born_transactional && !error &&
1490 (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1491 T_ZEROFILL)))
1492 error= write_log_record(param);
1493
1494 if (param->not_visible_rows_found && (param->testflag & T_VERBOSE))
1495 {
1496 char buff[22];
1497 printf("Max transaction id found: %s\n",
1498 llstr(param->max_found_trid, buff));
1499 }
1500
1501 fflush(stdout);
1502 fflush(stderr);
1503
1504 if (param->error_printed)
1505 {
1506 error= 2;
1507 if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1508 {
1509 fprintf(stderr, "Aria table '%s' is not fixed because of errors\n",
1510 filename);
1511 if (param->testflag & T_REP_ANY)
1512 fprintf(stderr, "Try fixing it by using the --safe-recover (-o), "
1513 "the --force (-f) option or by not using the --quick (-q) "
1514 "flag\n");
1515 }
1516 else if (!(param->testflag & T_FORCE_CREATE))
1517 fprintf(stderr, "Aria table '%s' is corrupted\nFix it using switch "
1518 "\"-r\" or \"-o\"\n", filename);
1519 }
1520 else if ((param->warning_printed || warning_printed_by_chk_status) &&
1521 ! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1522 T_FORCE_CREATE)))
1523 {
1524 if (!error)
1525 error= 1;
1526 (void) fprintf(stderr, "Aria table '%s' is usable but should be fixed\n",
1527 filename);
1528 }
1529
1530 (void) fflush(stderr);
1531 DBUG_RETURN(error);
1532 } /* maria_chk */
1533
1534
1535 /* Write info about table */
1536
descript(HA_CHECK * param,register MARIA_HA * info,char * name)1537 static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
1538 {
1539 uint key,keyseg_nr,field;
1540 reg3 MARIA_KEYDEF *keyinfo;
1541 reg2 HA_KEYSEG *keyseg;
1542 reg4 const char *text;
1543 char buff[200],length[10],*pos,*end;
1544 enum en_fieldtype type;
1545 MARIA_SHARE *share= info->s;
1546 char llbuff[22],llbuff2[22];
1547 DBUG_ENTER("descript");
1548
1549 if (param->testflag & T_VERY_SILENT)
1550 {
1551 longlong checksum= info->state->checksum;
1552 if (!(share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
1553 checksum= 0;
1554 printf("%s %s %s\n", name, llstr(info->state->records,llbuff),
1555 llstr(checksum, llbuff2));
1556 DBUG_VOID_RETURN;
1557 }
1558
1559 printf("Aria file: %s\n",name);
1560 printf("Record format: %s\n", record_formats[share->data_file_type]);
1561 printf("Crashsafe: %s\n",
1562 share->base.born_transactional ? "yes" : "no");
1563 printf("Character set: %s (%d)\n",
1564 get_charset_name(share->base.language),
1565 (int) share->base.language);
1566
1567 if (param->testflag & T_VERBOSE)
1568 {
1569 if (share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED)
1570 printf("Encrypted: yes\n");
1571 printf("File-version: %d\n",
1572 (int) share->state.header.file_version[3]);
1573 if (share->state.create_time)
1574 {
1575 get_date(buff,1,share->state.create_time);
1576 printf("Creation time: %s\n",buff);
1577 }
1578 if (share->state.check_time)
1579 {
1580 get_date(buff,1,share->state.check_time);
1581 printf("Check/recover time: %s\n",buff);
1582 }
1583 if (share->base.born_transactional)
1584 {
1585 printf("LSNs: create_rename " LSN_FMT ","
1586 " state_horizon " LSN_FMT ", skip_redo " LSN_FMT "\n",
1587 LSN_IN_PARTS(share->state.create_rename_lsn),
1588 LSN_IN_PARTS(share->state.is_of_horizon),
1589 LSN_IN_PARTS(share->state.skip_redo_lsn));
1590 printf("create_trid: %s\n",
1591 llstr(share->state.create_trid, llbuff));
1592 }
1593 compile_time_assert((MY_UUID_STRING_LENGTH + 1) <= sizeof(buff));
1594 buff[MY_UUID_STRING_LENGTH]= 0;
1595 my_uuid2str(share->base.uuid, buff);
1596 printf("UUID: %s\n", buff);
1597 pos=buff;
1598 if (share->state.changed & STATE_CRASHED)
1599 strmov(buff, share->state.changed & STATE_CRASHED_ON_REPAIR ?
1600 "crashed on repair" : "crashed");
1601 else if (have_control_file &&
1602 (share->state.changed & (STATE_MOVED | STATE_NOT_ZEROFILLED)) ==
1603 (STATE_MOVED | STATE_NOT_ZEROFILLED))
1604 strmov(buff, "moved from another system. Use --zerofill to fix it");
1605 else
1606 {
1607 if (share->state.open_count)
1608 pos=strmov(pos,"open,");
1609 if (share->state.changed & STATE_CHANGED)
1610 pos=strmov(pos,"changed,");
1611 else
1612 pos=strmov(pos,"checked,");
1613 if (!(share->state.changed & STATE_NOT_ANALYZED))
1614 pos=strmov(pos,"analyzed,");
1615 if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1616 pos=strmov(pos,"optimized keys,");
1617 if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1618 pos=strmov(pos,"sorted index pages,");
1619 if (!(share->state.changed & STATE_NOT_ZEROFILLED))
1620 pos=strmov(pos,"zerofilled,");
1621 if (!(share->state.changed & STATE_NOT_MOVABLE))
1622 pos=strmov(pos,"movable,");
1623 if (have_control_file && (share->state.changed & STATE_MOVED))
1624 pos=strmov(pos,"moved,");
1625 pos[-1]=0; /* Remove extra ',' */
1626 }
1627 printf("Status: %s\n",buff);
1628 if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1629 printf("Checksum: %26s\n",llstr(info->state->checksum,llbuff));
1630 ;
1631 if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1632 printf("Keys are only flushed at close\n");
1633
1634 if (share->options & HA_OPTION_PAGE_CHECKSUM)
1635 printf("Page checksums are used\n");
1636 if (share->base.auto_key)
1637 {
1638 printf("Auto increment key: %16d Last value: %18s\n",
1639 share->base.auto_key,
1640 llstr(share->state.auto_increment,llbuff));
1641 }
1642 }
1643 printf("Data records: %16s Deleted blocks: %18s\n",
1644 llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1645 if (param->testflag & T_SILENT)
1646 DBUG_VOID_RETURN; /* This is enough */
1647
1648 if (param->testflag & T_VERBOSE)
1649 {
1650 #ifdef USE_RELOC
1651 printf("Init-relocation: %16s\n",llstr(share->base.reloc,llbuff));
1652 #endif
1653 printf("Datafile parts: %16s Deleted data: %18s\n",
1654 llstr(share->state.split,llbuff),
1655 llstr(info->state->empty,llbuff2));
1656 printf("Datafile pointer (bytes): %11d Keyfile pointer (bytes): %13d\n",
1657 share->rec_reflength,share->base.key_reflength);
1658 printf("Datafile length: %16s Keyfile length: %18s\n",
1659 llstr(info->state->data_file_length,llbuff),
1660 llstr(info->state->key_file_length,llbuff2));
1661
1662 if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1663 puts("This is a one-record table");
1664 else
1665 {
1666 if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1667 share->base.max_key_file_length != HA_OFFSET_ERROR)
1668 printf("Max datafile length: %16s Max keyfile length: %18s\n",
1669 ullstr(share->base.max_data_file_length,llbuff),
1670 ullstr(share->base.max_key_file_length,llbuff2));
1671 }
1672 }
1673 printf("Block_size: %16d\n",(int) share->block_size);
1674 printf("Recordlength: %16d\n",(int) share->base.pack_reclength);
1675 if (! maria_is_all_keys_active(share->state.key_map, share->base.keys))
1676 {
1677 longlong2str(share->state.key_map,buff,2);
1678 printf("Using only keys '%s' of %d possibly keys\n",
1679 buff, share->base.keys);
1680 }
1681 puts("\nTable description:");
1682 printf("Key Start Len Index Type");
1683 if (param->testflag & T_VERBOSE)
1684 printf(" Rec/key Root Blocksize");
1685 putchar('\n');
1686
1687 for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1688 key < share->base.keys;
1689 key++,keyinfo++)
1690 {
1691 keyseg=keyinfo->seg;
1692 if (keyinfo->flag & HA_NOSAME) text="unique ";
1693 else if (keyinfo->flag & HA_FULLTEXT) text="fulltext ";
1694 else text="multip.";
1695
1696 pos=buff;
1697 if (keyseg->flag & HA_REVERSE_SORT)
1698 *pos++ = '-';
1699 pos=strmov(pos,type_names[keyseg->type]);
1700 *pos++ = ' ';
1701 *pos=0;
1702 if (keyinfo->flag & HA_PACK_KEY)
1703 pos=strmov(pos,prefix_packed_txt);
1704 if (keyinfo->flag & HA_BINARY_PACK_KEY)
1705 pos=strmov(pos,bin_packed_txt);
1706 if (keyseg->flag & HA_SPACE_PACK)
1707 pos=strmov(pos,diff_txt);
1708 if (keyseg->flag & HA_BLOB_PART)
1709 pos=strmov(pos,blob_txt);
1710 if (keyseg->flag & HA_NULL_PART)
1711 pos=strmov(pos,null_txt);
1712 *pos=0;
1713
1714 printf("%-4d%-6ld%-3d %-9s%-23s",
1715 key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1716 if (share->state.key_root[key] != HA_OFFSET_ERROR)
1717 llstr(share->state.key_root[key],buff);
1718 else
1719 buff[0]=0;
1720 if (param->testflag & T_VERBOSE)
1721 printf("%9.0f %12s %10d",
1722 share->state.rec_per_key_part[keyseg_nr++],
1723 buff,keyinfo->block_length);
1724 putchar('\n');
1725 while ((++keyseg)->type != HA_KEYTYPE_END)
1726 {
1727 pos=buff;
1728 if (keyseg->flag & HA_REVERSE_SORT)
1729 *pos++ = '-';
1730 pos=strmov(pos,type_names[keyseg->type]);
1731 *pos++= ' ';
1732 if (keyseg->flag & HA_SPACE_PACK)
1733 pos=strmov(pos,diff_txt);
1734 if (keyseg->flag & HA_BLOB_PART)
1735 pos=strmov(pos,blob_txt);
1736 if (keyseg->flag & HA_NULL_PART)
1737 pos=strmov(pos,null_txt);
1738 *pos=0;
1739 printf(" %-6ld%-3d %-21s",
1740 (long) keyseg->start+1,keyseg->length,buff);
1741 if (param->testflag & T_VERBOSE)
1742 printf("%11.0f", share->state.rec_per_key_part[keyseg_nr++]);
1743 putchar('\n');
1744 }
1745 keyseg++;
1746 }
1747 if (share->state.header.uniques)
1748 {
1749 MARIA_UNIQUEDEF *uniqueinfo;
1750 puts("\nUnique Key Start Len Nullpos Nullbit Type");
1751 for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1752 key < share->state.header.uniques; key++, uniqueinfo++)
1753 {
1754 my_bool new_row=0;
1755 char null_bit[8],null_pos[8];
1756 printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1757 for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1758 {
1759 if (new_row)
1760 fputs(" ",stdout);
1761 null_bit[0]=null_pos[0]=0;
1762 if (keyseg->null_bit)
1763 {
1764 my_snprintf(null_bit, sizeof(null_bit), "%d", keyseg->null_bit);
1765 my_snprintf(null_pos, sizeof(null_pos), "%ld", (long) keyseg->null_pos+1);
1766 }
1767 printf("%-7ld%-5d%-9s%-10s%-30s\n",
1768 (long) keyseg->start+1,keyseg->length,
1769 null_pos,null_bit,
1770 type_names[keyseg->type]);
1771 new_row=1;
1772 }
1773 }
1774 }
1775 if (param->verbose > 1)
1776 {
1777 char null_bit[8],null_pos[8];
1778 printf("\nField Start Length Nullpos Nullbit Type");
1779 if (share->options & HA_OPTION_COMPRESS_RECORD)
1780 printf(" Huff tree Bits");
1781 putchar('\n');
1782
1783 for (field=0 ; field < share->base.fields ; field++)
1784 {
1785 if (share->options & HA_OPTION_COMPRESS_RECORD)
1786 type=share->columndef[field].base_type;
1787 else
1788 type=(enum en_fieldtype) share->columndef[field].type;
1789 end= strmov(buff, field_pack[type]);
1790 if (end != buff)
1791 {
1792 *(end++)=',';
1793 *(end++)=' ';
1794 }
1795 if (share->options & HA_OPTION_COMPRESS_RECORD)
1796 {
1797 if (share->columndef[field].pack_type & PACK_TYPE_SELECTED)
1798 end=strmov(end,"not_always, ");
1799 if (share->columndef[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1800 end=strmov(end,"no empty, ");
1801 if (share->columndef[field].pack_type & PACK_TYPE_ZERO_FILL)
1802 {
1803 sprintf(end,"zerofill(%d), ",share->columndef[field].space_length_bits);
1804 end=strend(end);
1805 }
1806 }
1807 if (end != buff)
1808 end[-2]= 0;
1809 int10_to_str((long) share->columndef[field].length,length,10);
1810 null_bit[0]=null_pos[0]=0;
1811 if (share->columndef[field].null_bit)
1812 {
1813 sprintf(null_bit,"%d",share->columndef[field].null_bit);
1814 sprintf(null_pos,"%d",share->columndef[field].null_pos+1);
1815 }
1816 printf("%-6d%-6u%-7s%-8s%-8s%-35s",field+1,
1817 (uint) share->columndef[field].offset+1,
1818 length, null_pos, null_bit, buff);
1819 if (share->options & HA_OPTION_COMPRESS_RECORD)
1820 {
1821 if (share->columndef[field].huff_tree)
1822 printf("%3d %2d",
1823 (uint) (share->columndef[field].huff_tree-share->decode_trees)+1,
1824 share->columndef[field].huff_tree->quick_table_bits);
1825 }
1826 putchar('\n');
1827 }
1828 if (share->data_file_type == BLOCK_RECORD)
1829 {
1830 uint i;
1831 puts("\nBitmap Data size Description");
1832 for (i=0 ; i <= 7 ; i++)
1833 printf("%u %5u %s\n", i, share->bitmap.sizes[i],
1834 bitmap_description[i]);
1835 }
1836 }
1837 DBUG_VOID_RETURN;
1838 } /* describe */
1839
1840
1841 /* Sort records according to one key */
1842
maria_sort_records(HA_CHECK * param,register MARIA_HA * info,char * name,uint sort_key,my_bool write_info,my_bool update_index)1843 static int maria_sort_records(HA_CHECK *param,
1844 register MARIA_HA *info, char *name,
1845 uint sort_key,
1846 my_bool write_info,
1847 my_bool update_index)
1848 {
1849 int got_error;
1850 uint key;
1851 MARIA_KEYDEF *keyinfo;
1852 File new_file;
1853 uchar *temp_buff;
1854 ha_rows old_record_count;
1855 MARIA_SHARE *share= info->s;
1856 char llbuff[22],llbuff2[22];
1857 MARIA_SORT_INFO sort_info;
1858 MARIA_SORT_PARAM sort_param;
1859 MARIA_PAGE page;
1860 DBUG_ENTER("sort_records");
1861
1862 bzero((char*)&sort_info,sizeof(sort_info));
1863 bzero((char*)&sort_param,sizeof(sort_param));
1864 sort_param.sort_info=&sort_info;
1865 sort_info.param=param;
1866 keyinfo= &share->keyinfo[sort_key];
1867 got_error=1;
1868 temp_buff=0;
1869 new_file= -1;
1870
1871 if (! maria_is_key_active(share->state.key_map, sort_key))
1872 {
1873 _ma_check_print_warning(param,
1874 "Can't sort table '%s' on key %d; No such key",
1875 name,sort_key+1);
1876 param->error_printed=0;
1877 DBUG_RETURN(0); /* Nothing to do */
1878 }
1879 if (keyinfo->flag & HA_FULLTEXT)
1880 {
1881 _ma_check_print_warning(param,"Can't sort table '%s' on FULLTEXT key %d",
1882 name,sort_key+1);
1883 param->error_printed=0;
1884 DBUG_RETURN(0); /* Nothing to do */
1885 }
1886 if (keyinfo->flag & HA_BINARY_PACK_KEY)
1887 {
1888 _ma_check_print_warning(param,
1889 "Can't sort table '%s' on a key with prefix "
1890 "packing %d",
1891 name,sort_key+1);
1892 param->error_printed=0;
1893 DBUG_RETURN(0);
1894 }
1895
1896
1897 if (share->data_file_type == COMPRESSED_RECORD)
1898 {
1899 _ma_check_print_warning(param,"Can't sort read-only table '%s'", name);
1900 param->error_printed=0;
1901 DBUG_RETURN(0); /* Nothing to do */
1902 }
1903 if (!(param->testflag & T_SILENT))
1904 {
1905 printf("- Sorting records for Aria table '%s'\n",name);
1906 if (write_info)
1907 printf("Data records: %9s Deleted: %9s\n",
1908 llstr(info->state->records,llbuff),
1909 llstr(info->state->del,llbuff2));
1910 }
1911 if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1912 DBUG_RETURN(0); /* Nothing to do */
1913
1914 if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1915 WRITE_CACHE,share->pack.header_length,1,
1916 MYF(MY_WME | MY_WAIT_IF_FULL)))
1917 goto err;
1918 info->opt_flag|=WRITE_CACHE_USED;
1919
1920 if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1921 {
1922 _ma_check_print_error(param,"Not enough memory for key block");
1923 goto err;
1924 }
1925
1926 if (!(sort_param.record= (uchar*) my_malloc(PSI_INSTRUMENT_ME,
1927 (uint) share->base.default_rec_buff_size, MYF(0))))
1928 {
1929 _ma_check_print_error(param,"Not enough memory for record");
1930 goto err;
1931 }
1932
1933 fn_format(param->temp_filename,name,"", MARIA_NAME_DEXT,2+4+32);
1934 new_file= mysql_file_create(key_file_tmp,
1935 fn_format(param->temp_filename,
1936 param->temp_filename, "",
1937 DATA_TMP_EXT,
1938 MY_REPLACE_EXT | MY_UNPACK_FILENAME),
1939 0, param->tmpfile_createflag, MYF(0));
1940 if (new_file < 0)
1941 {
1942 _ma_check_print_error(param,"Can't create new tempfile: '%s'",
1943 param->temp_filename);
1944 goto err;
1945 }
1946 if (share->pack.header_length)
1947 if (maria_filecopy(param, new_file, info->dfile.file, 0L,
1948 share->pack.header_length,
1949 "datafile-header"))
1950 goto err;
1951 info->rec_cache.file=new_file; /* Use this file for cacheing*/
1952
1953 maria_lock_memory(param);
1954 for (key=0 ; key < share->base.keys ; key++)
1955 share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1956
1957 if (mysql_file_pread(share->kfile.file, temp_buff,
1958 (uint) keyinfo->block_length,
1959 share->state.key_root[sort_key],
1960 MYF(MY_NABP+MY_WME)))
1961 {
1962 _ma_check_print_error(param, "Can't read indexpage from filepos: %s",
1963 llstr(share->state.key_root[sort_key], llbuff));
1964 goto err;
1965 }
1966
1967 /* Setup param for _ma_sort_write_record */
1968 sort_info.info=info;
1969 sort_info.new_data_file_type=share->data_file_type;
1970 sort_param.fix_datafile=1;
1971 sort_param.master=1;
1972 sort_param.filepos=share->pack.header_length;
1973 old_record_count=info->state->records;
1974 info->state->records=0;
1975 if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1976 info->state->checksum=0;
1977
1978 _ma_page_setup(&page, info, keyinfo, share->state.key_root[sort_key],
1979 temp_buff);
1980 if (sort_record_index(&sort_param, &page, sort_key,new_file,update_index) ||
1981 maria_write_data_suffix(&sort_info,1) ||
1982 flush_io_cache(&info->rec_cache))
1983 goto err;
1984
1985 if (info->state->records != old_record_count)
1986 {
1987 _ma_check_print_error(param,"found %s of %s records",
1988 llstr(info->state->records,llbuff),
1989 llstr(old_record_count,llbuff2));
1990 goto err;
1991 }
1992
1993 mysql_file_close(info->dfile.file, MYF(MY_WME));
1994 param->out_flag|=O_NEW_DATA; /* Data in new file */
1995 info->dfile.file= new_file; /* Use new datafile */
1996 _ma_set_data_pagecache_callbacks(&info->dfile, info->s);
1997
1998 info->state->del=0;
1999 info->state->empty=0;
2000 share->state.dellink= HA_OFFSET_ERROR;
2001 info->state->data_file_length=sort_param.filepos;
2002 share->state.split=info->state->records; /* Only hole records */
2003 share->state.version=(ulong) time((time_t*) 0);
2004
2005 info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
2006
2007 if (param->testflag & T_WRITE_LOOP)
2008 {
2009 fputs(" \r",stdout);
2010 fflush(stdout);
2011 }
2012 got_error=0;
2013
2014 err:
2015 if (got_error && new_file >= 0)
2016 {
2017 end_io_cache(&info->rec_cache);
2018 (void) mysql_file_close(new_file,MYF(MY_WME));
2019 (void) mysql_file_delete(key_file_tmp, param->temp_filename, MYF(MY_WME));
2020 }
2021 if (temp_buff)
2022 {
2023 my_afree(temp_buff);
2024 }
2025 my_free(sort_param.record);
2026 info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
2027 end_io_cache(&info->rec_cache);
2028 my_free(sort_info.buff);
2029 sort_info.buff=0;
2030 share->state.sortkey=sort_key;
2031 DBUG_RETURN(got_error);
2032 } /* sort_records */
2033
2034
2035 /* Sort records recursive using one index */
2036
sort_record_index(MARIA_SORT_PARAM * sort_param,MARIA_PAGE * ma_page,uint sort_key,File new_file,my_bool update_index)2037 static int sort_record_index(MARIA_SORT_PARAM *sort_param,
2038 MARIA_PAGE *ma_page, uint sort_key,
2039 File new_file,my_bool update_index)
2040 {
2041 MARIA_HA *info= ma_page->info;
2042 MARIA_SHARE *share= info->s;
2043 uint page_flag, nod_flag,used_length;
2044 my_bool buff_alloced;
2045 uchar *temp_buff,*keypos,*endpos;
2046 my_off_t next_page,rec_pos;
2047 uchar *lastkey;
2048 char llbuff[22];
2049 MARIA_SORT_INFO *sort_info= sort_param->sort_info;
2050 HA_CHECK *param=sort_info->param;
2051 MARIA_KEY tmp_key;
2052 MARIA_PAGE new_page;
2053 const MARIA_KEYDEF *keyinfo= ma_page->keyinfo;
2054 DBUG_ENTER("sort_record_index");
2055
2056 temp_buff=0;
2057 page_flag= ma_page->flag;
2058 nod_flag= ma_page->node;
2059 tmp_key.keyinfo= (MARIA_KEYDEF*) keyinfo;
2060
2061 alloc_on_stack(*info->stack_end_ptr, lastkey, buff_alloced,
2062 (nod_flag ? keyinfo->block_length : 0) +
2063 ALIGN_SIZE(keyinfo->max_store_length));
2064 if (!lastkey)
2065 {
2066 _ma_check_print_error(param,"Not Enough memory");
2067 DBUG_RETURN(-1);
2068 }
2069 if (nod_flag)
2070 temp_buff= lastkey + ALIGN_SIZE(keyinfo->max_store_length);
2071
2072 tmp_key.data= lastkey;
2073
2074 used_length= ma_page->size;
2075 keypos= ma_page->buff + share->keypage_header + nod_flag;
2076 endpos= ma_page->buff + used_length;
2077 for ( ;; )
2078 {
2079 if (nod_flag)
2080 {
2081 next_page= _ma_kpos(nod_flag, keypos);
2082 if (mysql_file_pread(share->kfile.file, temp_buff,
2083 (uint) tmp_key.keyinfo->block_length, next_page,
2084 MYF(MY_NABP+MY_WME)))
2085 {
2086 _ma_check_print_error(param,"Can't read keys from filepos: %s",
2087 llstr(next_page,llbuff));
2088 goto err;
2089 }
2090 _ma_page_setup(&new_page, info, ma_page->keyinfo, next_page, temp_buff);
2091
2092 if (sort_record_index(sort_param, &new_page, sort_key,
2093 new_file, update_index))
2094 goto err;
2095 }
2096 if (keypos >= endpos ||
2097 !(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos))
2098 break;
2099 rec_pos= _ma_row_pos_from_key(&tmp_key);
2100
2101 if ((*share->read_record)(info,sort_param->record,rec_pos))
2102 {
2103 _ma_check_print_error(param,"%d when reading datafile",my_errno);
2104 goto err;
2105 }
2106 if (rec_pos != sort_param->filepos && update_index)
2107 {
2108 _ma_dpointer(share, keypos - nod_flag - tmp_key.ref_length,
2109 sort_param->filepos);
2110 if (maria_movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
2111 sort_key))
2112 {
2113 _ma_check_print_error(param,"%d when updating key-pointers",my_errno);
2114 goto err;
2115 }
2116 }
2117 if (_ma_sort_write_record(sort_param))
2118 goto err;
2119 }
2120 /* Clear end of block to get better compression if the table is backuped */
2121 bzero(ma_page->buff + used_length, keyinfo->block_length - used_length);
2122 if (my_pwrite(share->kfile.file, ma_page->buff, (uint)keyinfo->block_length,
2123 ma_page->pos, param->myf_rw))
2124 {
2125 _ma_check_print_error(param,"%d when updating keyblock",my_errno);
2126 goto err;
2127 }
2128 stack_alloc_free(lastkey, buff_alloced);
2129 DBUG_RETURN(0);
2130
2131 err:
2132 stack_alloc_free(lastkey, buff_alloced);
2133 DBUG_RETURN(1);
2134 } /* sort_record_index */
2135
2136
write_log_record(HA_CHECK * param)2137 static my_bool write_log_record(HA_CHECK *param)
2138 {
2139 /*
2140 Now that all operations including O_NEW_DATA|INDEX are successfully
2141 done, we can write a log record.
2142 */
2143 MARIA_HA *info= maria_open(param->isam_file_name, O_RDWR, 0, 0);
2144 if (info == NULL)
2145 _ma_check_print_error(param, default_open_errmsg, my_errno,
2146 param->isam_file_name);
2147 else
2148 {
2149 if (write_log_record_for_repair(param, info))
2150 _ma_check_print_error(param, "%d when writing log record for"
2151 " Aria table '%s'", my_errno,
2152 param->isam_file_name);
2153 else if (maria_close(info))
2154 _ma_check_print_error(param, default_close_errmsg, my_errno,
2155 param->isam_file_name);
2156 else
2157 return FALSE;
2158 }
2159 return TRUE;
2160 }
2161
2162 #include "ma_check_standalone.h"
2163