1 # name : innodb_pass_corrupt_table.patch
2 # introduced : 11 or before
3 # maintainer : Yasufumi
6 # Any small change to this file in the main branch
7 # should be done or reviewed by the maintainer!
8 diff -ruN a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c
9 --- a/storage/innobase/btr/btr0btr.c 2010-11-03 07:01:13.000000000 +0900
10 +++ b/storage/innobase/btr/btr0btr.c 2010-12-04 15:38:18.110513593 +0900
12 root_page_no = dict_index_get_page(index);
14 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
16 + if (srv_pass_corrupt_table && !block) {
21 ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
22 == dict_table_is_comp(index->table));
26 root = btr_root_get(index, &mtr);
28 + if (srv_pass_corrupt_table && !root) {
34 if (flag == BTR_N_LEAF_PAGES) {
35 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
40 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
42 + if (srv_pass_corrupt_table && !root) {
49 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
54 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
56 + if (srv_pass_corrupt_table && !root) {
62 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
66 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
68 + if (srv_pass_corrupt_table && !block) {
73 btr_search_drop_page_hash_index(block);
75 header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP;
76 diff -ruN a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
77 --- a/storage/innobase/btr/btr0cur.c 2010-12-03 17:30:16.239038936 +0900
78 +++ b/storage/innobase/btr/btr0cur.c 2010-12-04 15:38:18.114551906 +0900
81 mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH;
82 get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
84 + if (srv_pass_corrupt_table && !get_block) {
89 ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
90 #endif /* UNIV_BTR_DEBUG */
92 get_block = btr_block_get(space, zip_size,
96 + if (srv_pass_corrupt_table && !get_block) {
100 #ifdef UNIV_BTR_DEBUG
101 ut_a(page_is_comp(get_block->frame)
102 == page_is_comp(page));
105 get_block = btr_block_get(space, zip_size, page_no,
108 + if (srv_pass_corrupt_table && !get_block) {
112 #ifdef UNIV_BTR_DEBUG
113 ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
114 #endif /* UNIV_BTR_DEBUG */
116 get_block = btr_block_get(space, zip_size,
120 + if (srv_pass_corrupt_table && !get_block) {
124 #ifdef UNIV_BTR_DEBUG
125 ut_a(page_is_comp(get_block->frame)
126 == page_is_comp(page));
128 get_block = btr_block_get(space, zip_size,
129 left_page_no, mode, mtr);
130 cursor->left_block = get_block;
132 + if (srv_pass_corrupt_table && !get_block) {
136 #ifdef UNIV_BTR_DEBUG
137 ut_a(page_is_comp(get_block->frame)
138 == page_is_comp(page));
142 get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
144 + if (srv_pass_corrupt_table && !get_block) {
148 #ifdef UNIV_BTR_DEBUG
149 ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
150 #endif /* UNIV_BTR_DEBUG */
155 + if (srv_pass_corrupt_table
156 + && buf_mode != BUF_GET_IF_IN_POOL
157 + && buf_mode != BUF_GET_IF_IN_POOL_OR_WATCH) {
158 + page_cursor->block = 0;
159 + page_cursor->rec = 0;
161 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
165 + ut_a(buf_mode == BUF_GET_IF_IN_POOL
166 + || buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH);
168 /* This must be a search to perform an insert/delete
169 mark/ delete; try using the insert/delete buffer */
172 block->check_index_page_at_flush = TRUE;
173 page = buf_block_get_frame(block);
175 + if (srv_pass_corrupt_table && !page) {
176 + page_cursor->block = 0;
177 + page_cursor->rec = 0;
179 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
185 if (rw_latch != RW_NO_LATCH) {
186 #ifdef UNIV_ZIP_DEBUG
187 const page_zip_des_t* page_zip
189 RW_NO_LATCH, NULL, BUF_GET,
191 page = buf_block_get_frame(block);
193 + if (srv_pass_corrupt_table && !page) {
194 + page_cursor->block = 0;
195 + page_cursor->rec = 0;
197 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
203 ut_ad(index->id == btr_page_get_index_id(page));
205 block->check_index_page_at_flush = TRUE;
206 @@ -974,6 +1038,14 @@
207 RW_NO_LATCH, NULL, BUF_GET,
209 page = buf_block_get_frame(block);
211 + if (srv_pass_corrupt_table && !page) {
212 + page_cursor->block = 0;
213 + page_cursor->rec = 0;
218 ut_ad(index->id == btr_page_get_index_id(page));
220 if (height == ULINT_UNDEFINED) {
221 @@ -1288,6 +1360,12 @@
224 block = btr_cur_get_block(cursor);
226 + if (srv_pass_corrupt_table && !block) {
227 + return(DB_CORRUPTION);
231 page = buf_block_get_frame(block);
232 index = cursor->index;
233 zip_size = buf_block_get_zip_size(block);
234 @@ -3013,6 +3091,11 @@
236 block = btr_cur_get_block(cursor);
238 + if (srv_pass_corrupt_table && !block) {
239 + return(DB_CORRUPTION);
243 ut_ad(page_is_leaf(buf_block_get_frame(block)));
245 rec = btr_cur_get_rec(cursor);
246 @@ -3817,6 +3900,11 @@
248 page = btr_cur_get_page(&cursor);
250 + if (srv_pass_corrupt_table && !page) {
255 supremum = page_get_supremum_rec(page);
256 if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS && is_first_page) {
257 /* the cursor should be the first record of the page. */
258 diff -ruN a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c
259 --- a/storage/innobase/btr/btr0pcur.c 2010-11-03 07:01:13.000000000 +0900
260 +++ b/storage/innobase/btr/btr0pcur.c 2010-12-04 15:38:18.116563877 +0900
266 +#include "srv0srv.h"
267 /**************************************************************//**
268 Allocates memory for a persistent cursor object and initializes the cursor.
269 @return own: persistent cursor */
271 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
273 block = btr_pcur_get_block(cursor);
275 + if (srv_pass_corrupt_table && !block) {
280 index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
282 page_cursor = btr_pcur_get_page_cur(cursor);
284 next_block = btr_block_get(space, zip_size, next_page_no,
285 cursor->latch_mode, mtr);
286 next_page = buf_block_get_frame(next_block);
288 + if (srv_pass_corrupt_table && !next_page) {
289 + btr_leaf_page_release(btr_pcur_get_block(cursor),
290 + cursor->latch_mode, mtr);
291 + btr_pcur_get_page_cur(cursor)->block = 0;
292 + btr_pcur_get_page_cur(cursor)->rec = 0;
296 #ifdef UNIV_BTR_DEBUG
297 ut_a(page_is_comp(next_page) == page_is_comp(page));
298 ut_a(btr_page_get_prev(next_page, mtr)
299 diff -ruN a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c
300 --- a/storage/innobase/btr/btr0sea.c 2010-12-03 15:49:59.166193407 +0900
301 +++ b/storage/innobase/btr/btr0sea.c 2010-12-04 15:38:18.118548961 +0900
303 #include "btr0pcur.h"
307 +#include "srv0srv.h"
308 /** Flag: has the search system been enabled?
309 Protected by btr_search_latch and btr_search_enabled_mutex. */
310 UNIV_INTERN char btr_search_enabled = TRUE;
313 block = btr_cur_get_block(cursor);
315 + if (srv_pass_corrupt_table && !block) {
320 /* NOTE that the following two function calls do NOT protect
321 info or block->n_fields etc. with any semaphore, to save CPU time!
322 We cannot assume the fields are consistent when we return from
323 diff -ruN a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c
324 --- a/storage/innobase/buf/buf0buf.c 2010-12-04 15:37:50.554565654 +0900
325 +++ b/storage/innobase/buf/buf0buf.c 2010-12-04 15:38:18.119548922 +0900
327 #include "log0recv.h"
328 #include "page0zip.h"
330 +#include "srv0start.h"
332 /* prototypes for new functions added to ha_innodb.cc */
333 trx_t* innobase_get_trx();
334 @@ -1131,6 +1132,11 @@
335 ready = buf_flush_ready_for_replace(&block->page);
336 mutex_exit(&block->mutex);
338 + if (block->page.is_corrupt) {
339 + /* corrupt page may remain, it can be skipped */
346 @@ -2476,6 +2482,14 @@
350 + if (srv_pass_corrupt_table) {
351 + if (bpage->is_corrupt) {
352 + rw_lock_s_unlock(&buf_pool->page_hash_latch);
356 + ut_a(!(bpage->is_corrupt));
358 block_mutex = buf_page_get_mutex_enter(bpage);
360 rw_lock_s_unlock(&buf_pool->page_hash_latch);
361 @@ -3023,6 +3037,14 @@
365 + if (srv_pass_corrupt_table) {
366 + if (block->page.is_corrupt) {
367 + mutex_exit(block_mutex);
371 + ut_a(!(block->page.is_corrupt));
373 switch (buf_block_get_state(block)) {
376 @@ -3690,6 +3712,7 @@
377 bpage->newest_modification = 0;
378 bpage->oldest_modification = 0;
379 HASH_INVALIDATE(bpage, hash);
380 + bpage->is_corrupt = FALSE;
381 #ifdef UNIV_DEBUG_FILE_ACCESSES
382 bpage->file_page_was_freed = FALSE;
383 #endif /* UNIV_DEBUG_FILE_ACCESSES */
384 @@ -4200,7 +4223,8 @@
386 buf_page_io_complete(
387 /*=================*/
388 - buf_page_t* bpage) /*!< in: pointer to the block in question */
389 + buf_page_t* bpage, /*!< in: pointer to the block in question */
392 enum buf_io_fix io_type;
393 buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
394 @@ -4279,6 +4303,7 @@
395 (ulong) bpage->offset);
398 + if (!srv_pass_corrupt_table || !bpage->is_corrupt) {
399 /* From version 3.23.38 up we store the page checksum
400 to the 4 first bytes of the page end lsn field */
402 @@ -4320,6 +4345,19 @@
403 REFMAN "forcing-innodb-recovery.html\n"
404 "InnoDB: about forcing recovery.\n", stderr);
406 + if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space)
407 + && bpage->space < SRV_LOG_SPACE_FIRST_ID) {
409 + "InnoDB: space %u will be treated as corrupt.\n",
411 + fil_space_set_corrupt(bpage->space);
412 + if (trx && trx->dict_operation_lock_mode == 0) {
413 + dict_table_set_corrupt_by_space(bpage->space, TRUE);
415 + dict_table_set_corrupt_by_space(bpage->space, FALSE);
417 + bpage->is_corrupt = TRUE;
419 if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
420 fputs("InnoDB: Ending processing because of"
421 " a corrupt database page.\n",
422 @@ -4327,6 +4365,7 @@
428 if (recv_recovery_is_on()) {
429 /* Pages must be uncompressed for crash recovery. */
430 @@ -4336,8 +4375,11 @@
432 if (uncompressed && !recv_no_ibuf_operations) {
433 ibuf_merge_or_delete_for_page(
434 + /* Delete possible entries, if bpage is_corrupt */
435 + (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
436 (buf_block_t*) bpage, bpage->space,
437 bpage->offset, buf_page_get_zip_size(bpage),
438 + (srv_pass_corrupt_table && bpage->is_corrupt) ? FALSE :
442 diff -ruN a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c
443 --- a/storage/innobase/buf/buf0rea.c 2010-12-04 15:37:50.557553380 +0900
444 +++ b/storage/innobase/buf/buf0rea.c 2010-12-04 15:41:09.784467585 +0900
445 @@ -193,12 +193,19 @@
446 ((buf_block_t*) bpage)->frame, bpage, trx);
450 + if (srv_pass_corrupt_table) {
451 + if (*err != DB_SUCCESS) {
452 + bpage->is_corrupt = TRUE;
455 ut_a(*err == DB_SUCCESS);
459 /* The i/o is already completed when we arrive from
461 - buf_page_io_complete(bpage);
462 + buf_page_io_complete(bpage, trx);
466 diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
467 --- a/storage/innobase/dict/dict0dict.c 2010-12-03 17:30:16.248987063 +0900
468 +++ b/storage/innobase/dict/dict0dict.c 2010-12-04 15:45:23.808513973 +0900
470 #include "srv0srv.h" /* srv_lower_case_table_names */
471 #include "m_ctype.h" /* my_isspace() */
472 #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
473 +#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
479 mutex_exit(&(dict_sys->mutex));
481 - if (table != NULL) {
482 + if (table != NULL && !table->is_corrupt) {
483 /* If table->ibd_file_missing == TRUE, this will
484 print an error message and return without doing
486 @@ -1294,7 +1295,7 @@
487 + dict_sys->size) > srv_dict_size_limit ) {
488 prev_table = UT_LIST_GET_PREV(table_LRU, table);
490 - if (table == self || table->n_mysql_handles_opened)
491 + if (table == self || table->n_mysql_handles_opened || table->is_corrupt)
494 cached_foreign_tables = 0;
495 @@ -4327,6 +4328,12 @@
496 heap = mem_heap_create(1000);
499 + if (table->is_corrupt) {
500 + ut_a(srv_pass_corrupt_table);
501 + mem_heap_free(heap);
505 size = btr_get_size(index, BTR_TOTAL_SIZE);
507 index->stat_index_size = size;
508 @@ -4446,6 +4453,12 @@
509 heap = mem_heap_create(1000);
512 + if (table->is_corrupt) {
513 + ut_a(srv_pass_corrupt_table);
514 + mem_heap_free(heap);
518 /*===========================================*/
520 dict_table_t* sys_stats;
521 @@ -4611,6 +4624,12 @@
522 || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
523 && dict_index_is_clust(index)))) {
526 + if (table->is_corrupt) {
527 + ut_a(srv_pass_corrupt_table);
531 size = btr_get_size(index, BTR_TOTAL_SIZE);
533 index->stat_index_size = size;
534 @@ -5331,4 +5350,42 @@
535 rw_lock_free(&dict_table_stats_latches[i]);
539 +/*************************************************************************
540 +set is_corrupt flag by space_id*/
543 +dict_table_set_corrupt_by_space(
544 +/*============================*/
548 + dict_table_t* table;
549 + ibool found = FALSE;
551 + ut_a(!trx_sys_sys_space(space_id) && space_id < SRV_LOG_SPACE_FIRST_ID);
554 + mutex_enter(&(dict_sys->mutex));
556 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
559 + if (table->space == space_id) {
560 + table->is_corrupt = TRUE;
564 + table = UT_LIST_GET_NEXT(table_LRU, table);
568 + mutex_exit(&(dict_sys->mutex));
571 + fprintf(stderr, "InnoDB: space to be marked as "
572 + "crashed was not found for id %lu.\n",
576 #endif /* !UNIV_HOTBACKUP */
577 diff -ruN a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c
578 --- a/storage/innobase/dict/dict0mem.c 2010-11-03 07:01:13.000000000 +0900
579 +++ b/storage/innobase/dict/dict0mem.c 2010-12-04 15:38:18.126549463 +0900
581 /* The number of transactions that are either waiting on the
582 AUTOINC lock or have been granted the lock. */
583 table->n_waiting_or_granted_auto_inc_locks = 0;
585 + table->is_corrupt = FALSE;
586 #endif /* !UNIV_HOTBACKUP */
588 ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
589 diff -ruN a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
590 --- a/storage/innobase/fil/fil0fil.c 2010-12-04 15:37:50.564551587 +0900
591 +++ b/storage/innobase/fil/fil0fil.c 2010-12-04 15:38:18.128549252 +0900
593 file we have written to */
594 ibool is_in_unflushed_spaces; /*!< TRUE if this space is
595 currently in unflushed_spaces */
597 UT_LIST_NODE_T(fil_space_t) space_list;
598 /*!< list of all spaces */
599 ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
600 @@ -1291,6 +1292,8 @@
601 ut_fold_string(name), space);
602 space->is_in_unflushed_spaces = FALSE;
604 + space->is_corrupt = FALSE;
606 UT_LIST_ADD_LAST(space_list, fil_system->space_list, space);
608 mutex_exit(&fil_system->mutex);
609 @@ -4945,6 +4948,22 @@
610 ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
611 ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
613 + if (srv_pass_corrupt_table && space->is_corrupt) {
614 + /* should ignore i/o for the crashed space */
615 + mutex_enter(&fil_system->mutex);
616 + fil_node_complete_io(node, fil_system, type);
617 + mutex_exit(&fil_system->mutex);
618 + if (mode == OS_AIO_NORMAL) {
619 + ut_a(space->purpose == FIL_TABLESPACE);
620 + buf_page_io_complete(message, trx);
622 + if (type == OS_FILE_READ) {
623 + return(DB_TABLESPACE_DELETED);
625 + return(DB_SUCCESS);
628 + ut_a(!space->is_corrupt);
629 #ifdef UNIV_HOTBACKUP
630 /* In ibbackup do normal i/o, not aio */
631 if (type == OS_FILE_READ) {
632 @@ -4959,6 +4978,8 @@
633 ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
634 offset_low, offset_high, len, node, message, trx);
640 if (mode == OS_AIO_SYNC) {
641 @@ -5100,7 +5121,7 @@
643 if (fil_node->space->purpose == FIL_TABLESPACE) {
644 srv_set_io_thread_op_info(segment, "complete io for buf page");
645 - buf_page_io_complete(message);
646 + buf_page_io_complete(message, NULL);
648 srv_set_io_thread_op_info(segment, "complete io for log");
649 log_io_complete(message);
650 @@ -5454,3 +5475,46 @@
655 +/*************************************************************************
656 +functions to access is_corrupt flag of fil_space_t*/
659 +fil_space_is_corrupt(
660 +/*=================*/
663 + fil_space_t* space;
666 + mutex_enter(&fil_system->mutex);
668 + space = fil_space_get_by_id(space_id);
670 + if (space && space->is_corrupt) {
674 + mutex_exit(&fil_system->mutex);
680 +fil_space_set_corrupt(
681 +/*==================*/
684 + fil_space_t* space;
686 + mutex_enter(&fil_system->mutex);
688 + space = fil_space_get_by_id(space_id);
691 + space->is_corrupt = TRUE;
694 + mutex_exit(&fil_system->mutex);
697 diff -ruN a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c
698 --- a/storage/innobase/fsp/fsp0fsp.c 2010-12-04 15:37:50.569480615 +0900
699 +++ b/storage/innobase/fsp/fsp0fsp.c 2010-12-04 15:38:18.131550103 +0900
701 ut_ad(id || !zip_size);
703 block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
705 + if (srv_pass_corrupt_table && !block) {
710 header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
711 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
714 fsp_header_t* sp_header;
716 block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
718 + if (srv_pass_corrupt_table && !block) {
723 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
725 sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
726 @@ -1866,6 +1878,11 @@
730 + if (srv_pass_corrupt_table && !page) {
731 + return(ULINT_UNDEFINED);
735 for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
737 inode = fsp_seg_inode_page_get_nth_inode(
738 @@ -1979,6 +1996,11 @@
740 page = buf_block_get_frame(block);
742 + if (srv_pass_corrupt_table && !page) {
747 n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
749 ut_a(n != ULINT_UNDEFINED);
750 @@ -2072,6 +2094,11 @@
752 inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
754 + if (srv_pass_corrupt_table && !inode) {
759 if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
762 @@ -2098,7 +2125,7 @@
765 = fseg_inode_try_get(header, space, zip_size, mtr);
767 + ut_a(srv_pass_corrupt_table || inode);
771 @@ -3304,6 +3331,11 @@
773 descr = xdes_get_descriptor(space, zip_size, page, mtr);
775 + if (srv_pass_corrupt_table && !descr) {
776 + /* The page may be corrupt. pass it. */
781 if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
782 fputs("InnoDB: Dump of the tablespace extent descriptor: ",
783 @@ -3551,6 +3583,11 @@
785 descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
787 + if (srv_pass_corrupt_table && !descr) {
788 + /* The page may be corrupt. pass it. */
792 /* Check that the header resides on a page which has not been
795 @@ -3635,6 +3672,12 @@
797 inode = fseg_inode_get(header, space, zip_size, mtr);
799 + if (srv_pass_corrupt_table && !inode) {
800 + /* ignore the corruption */
805 descr = fseg_get_first_extent(inode, space, zip_size, mtr);
808 diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
809 --- a/storage/innobase/handler/ha_innodb.cc 2010-12-04 15:37:50.578486593 +0900
810 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-04 15:38:18.137549396 +0900
811 @@ -3928,6 +3928,12 @@
815 + if (share->ib_table && share->ib_table->is_corrupt) {
818 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
821 /* Create buffers for packing the fields of a record. Why
822 table->reclength did not work here? Obviously, because char
823 fields when packed actually became 1 byte longer, when we also
824 @@ -3955,6 +3961,19 @@
825 /* Get pointer to a table object in InnoDB dictionary cache */
826 ib_table = dict_table_get(norm_name, TRUE);
828 + if (ib_table && ib_table->is_corrupt) {
832 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
835 + if (share->ib_table) {
836 + ut_a(share->ib_table == ib_table);
838 + share->ib_table = ib_table;
841 if (NULL == ib_table) {
842 if (is_part && retries < 10) {
844 @@ -5119,6 +5138,10 @@
846 ha_statistic_increment(&SSV::ha_write_count);
848 + if (share->ib_table->is_corrupt) {
849 + DBUG_RETURN(HA_ERR_CRASHED);
852 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
853 table->timestamp_field->set_time();
855 @@ -5336,6 +5359,10 @@
857 innobase_active_small();
859 + if (share->ib_table->is_corrupt) {
860 + DBUG_RETURN(HA_ERR_CRASHED);
863 DBUG_RETURN(error_result);
866 @@ -5512,6 +5539,10 @@
868 ha_statistic_increment(&SSV::ha_update_count);
870 + if (share->ib_table->is_corrupt) {
871 + DBUG_RETURN(HA_ERR_CRASHED);
874 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
875 table->timestamp_field->set_time();
877 @@ -5601,6 +5632,10 @@
879 innobase_active_small();
881 + if (share->ib_table->is_corrupt) {
882 + DBUG_RETURN(HA_ERR_CRASHED);
888 @@ -5622,6 +5657,10 @@
890 ha_statistic_increment(&SSV::ha_delete_count);
892 + if (share->ib_table->is_corrupt) {
893 + DBUG_RETURN(HA_ERR_CRASHED);
896 if (!prebuilt->upd_node) {
897 row_get_prebuilt_update_vector(prebuilt);
899 @@ -5648,6 +5687,10 @@
901 innobase_active_small();
903 + if (share->ib_table->is_corrupt) {
904 + DBUG_RETURN(HA_ERR_CRASHED);
910 @@ -5887,6 +5930,10 @@
912 ha_statistic_increment(&SSV::ha_read_key_count);
914 + if (share->ib_table->is_corrupt) {
915 + DBUG_RETURN(HA_ERR_CRASHED);
918 index = prebuilt->index;
920 if (UNIV_UNLIKELY(index == NULL)) {
921 @@ -5952,6 +5999,10 @@
922 ret = DB_UNSUPPORTED;
925 + if (share->ib_table->is_corrupt) {
926 + DBUG_RETURN(HA_ERR_CRASHED);
932 @@ -6067,6 +6118,10 @@
934 DBUG_ENTER("change_active_index");
936 + if (share->ib_table->is_corrupt) {
937 + DBUG_RETURN(HA_ERR_CRASHED);
940 ut_ad(user_thd == ha_thd());
941 ut_a(prebuilt->trx == thd_to_trx(user_thd));
943 @@ -6157,6 +6212,10 @@
945 DBUG_ENTER("general_fetch");
947 + if (share->ib_table->is_corrupt) {
948 + DBUG_RETURN(HA_ERR_CRASHED);
951 ut_a(prebuilt->trx == thd_to_trx(user_thd));
953 innodb_srv_conc_enter_innodb(prebuilt->trx);
954 @@ -6166,6 +6225,10 @@
956 innodb_srv_conc_exit_innodb(prebuilt->trx);
958 + if (share->ib_table->is_corrupt) {
959 + DBUG_RETURN(HA_ERR_CRASHED);
965 @@ -7436,10 +7499,18 @@
967 update_thd(ha_thd());
969 + if (share->ib_table->is_corrupt) {
970 + DBUG_RETURN(HA_ERR_CRASHED);
973 /* Truncate the table in InnoDB */
975 error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
977 + if (share->ib_table->is_corrupt) {
978 + DBUG_RETURN(HA_ERR_CRASHED);
981 error = convert_error_code_to_mysql(error, prebuilt->table->flags,
984 @@ -7944,6 +8015,16 @@
985 return(ranges + (double) rows / (double) total_rows * time_for_scan);
990 +ha_innobase::is_corrupt() const
992 + if (share->ib_table)
993 + return ((bool)share->ib_table->is_corrupt);
998 /*********************************************************************//**
999 Calculates the key number used inside MySQL for an Innobase index. We will
1000 first check the "index translation table" for a match of the index to get
1001 @@ -8062,7 +8143,7 @@
1002 ib_table = prebuilt->table;
1004 if (flag & HA_STATUS_TIME) {
1005 - if (called_from_analyze || innobase_stats_on_metadata) {
1006 + if ((called_from_analyze || innobase_stats_on_metadata) && !share->ib_table->is_corrupt) {
1007 /* In sql_show we call with this flag: update
1008 then statistics so that they are up-to-date */
1010 @@ -8356,10 +8437,18 @@
1011 THD* thd, /*!< in: connection thread handle */
1012 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
1014 + if (share->ib_table->is_corrupt) {
1015 + return(HA_ADMIN_CORRUPT);
1018 /* Simply call ::info() with all the flags */
1019 info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
1020 true /* called from analyze */);
1022 + if (share->ib_table->is_corrupt) {
1023 + return(HA_ADMIN_CORRUPT);
1029 @@ -8541,6 +8630,10 @@
1030 my_error(ER_QUERY_INTERRUPTED, MYF(0));
1033 + if (share->ib_table->is_corrupt) {
1034 + return(HA_ADMIN_CORRUPT);
1037 DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
1040 @@ -9311,6 +9404,10 @@
1044 + if (share->ib_table->is_corrupt) {
1045 + DBUG_RETURN(HA_ERR_CRASHED);
1048 if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) {
1049 ut_print_timestamp(stderr);
1051 @@ -11720,6 +11817,25 @@
1052 "0 (the default) disables automatic dumps.",
1053 NULL, NULL, 0, 0, UINT_MAX32, 0);
1055 +const char *corrupt_table_action_names[]=
1061 +TYPELIB corrupt_table_action_typelib=
1063 + array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib",
1064 + corrupt_table_action_names, NULL
1066 +static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
1067 + PLUGIN_VAR_RQCMDARG,
1068 + "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, "
1069 + "when used with file_per_table. "
1070 + "All file io for the datafile after detected as corrupt are disabled, "
1071 + "except for the deletion.",
1072 + NULL, NULL, 0, &corrupt_table_action_typelib);
1074 static struct st_mysql_sys_var* innobase_system_variables[]= {
1075 MYSQL_SYSVAR(additional_mem_pool_size),
1076 MYSQL_SYSVAR(autoextend_increment),
1077 @@ -11806,6 +11922,7 @@
1078 MYSQL_SYSVAR(buffer_pool_restore_at_startup),
1079 MYSQL_SYSVAR(purge_threads),
1080 MYSQL_SYSVAR(purge_batch_size),
1081 + MYSQL_SYSVAR(corrupt_table_action),
1085 diff -ruN a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
1086 --- a/storage/innobase/handler/ha_innodb.h 2010-11-03 07:01:13.000000000 +0900
1087 +++ b/storage/innobase/handler/ha_innodb.h 2010-12-04 15:38:18.159588579 +0900
1089 innodb_idx_translate_t idx_trans_tbl; /*!< index translation
1090 table between MySQL and
1092 + dict_table_t* ib_table;
1099 double read_time(uint index, uint ranges, ha_rows rows);
1100 + bool is_corrupt() const;
1102 int write_row(uchar * buf);
1103 int update_row(const uchar * old_data, uchar * new_data);
1104 diff -ruN a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic
1105 --- a/storage/innobase/include/btr0btr.ic 2010-11-03 07:01:13.000000000 +0900
1106 +++ b/storage/innobase/include/btr0btr.ic 2010-12-04 15:38:18.162515035 +0900
1108 #include "mtr0mtr.h"
1109 #include "mtr0log.h"
1110 #include "page0zip.h"
1112 +#include "srv0srv.h"
1113 #define BTR_MAX_NODE_LEVEL 50 /*!< Maximum B-tree page level
1114 (not really a hard limit).
1115 Used in debug assertions
1117 block = buf_page_get_gen(space, zip_size, page_no, mode,
1118 NULL, BUF_GET, file, line, mtr);
1120 - if (mode != RW_NO_LATCH) {
1121 + ut_a(srv_pass_corrupt_table || block);
1123 + if (block && mode != RW_NO_LATCH) {
1125 buf_block_dbg_add_level(block, SYNC_TREE_NODE);
1127 diff -ruN a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
1128 --- a/storage/innobase/include/buf0buf.h 2010-12-03 15:49:59.218956083 +0900
1129 +++ b/storage/innobase/include/buf0buf.h 2010-12-04 15:38:18.164513667 +0900
1131 const buf_block_t* block) /*!< in: pointer to the control block */
1132 __attribute__((pure));
1133 #else /* UNIV_DEBUG */
1134 -# define buf_block_get_frame(block) (block)->frame
1135 +# define buf_block_get_frame(block) (block ? (block)->frame : 0)
1136 #endif /* UNIV_DEBUG */
1137 /*********************************************************************//**
1138 Gets the space id of a block.
1139 @@ -1116,7 +1116,8 @@
1141 buf_page_io_complete(
1142 /*=================*/
1143 - buf_page_t* bpage); /*!< in: pointer to the block in question */
1144 + buf_page_t* bpage, /*!< in: pointer to the block in question */
1146 /********************************************************************//**
1147 Calculates a folded value of a file page address to use in the page hash
1149 @@ -1431,6 +1432,7 @@
1150 0 if the block was never accessed
1151 in the buffer pool */
1154 # ifdef UNIV_DEBUG_FILE_ACCESSES
1155 ibool file_page_was_freed;
1156 /*!< this is set to TRUE when fsp
1157 diff -ruN a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
1158 --- a/storage/innobase/include/buf0buf.ic 2010-12-03 15:49:59.221956024 +0900
1159 +++ b/storage/innobase/include/buf0buf.ic 2010-12-04 15:38:18.167513925 +0900
1161 #include "buf0flu.h"
1162 #include "buf0lru.h"
1163 #include "buf0rea.h"
1165 +#include "srv0srv.h"
1166 /*********************************************************************//**
1167 Gets the current size of buffer buf_pool in bytes.
1168 @return size in bytes */
1169 @@ -617,6 +617,12 @@
1170 /*================*/
1171 const buf_block_t* block) /*!< in: pointer to the control block */
1173 + ut_a(srv_pass_corrupt_table || block);
1175 + if (srv_pass_corrupt_table && !block) {
1181 switch (buf_block_get_state(block)) {
1182 diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
1183 --- a/storage/innobase/include/dict0dict.h 2010-12-03 17:30:16.306955940 +0900
1184 +++ b/storage/innobase/include/dict0dict.h 2010-12-04 15:38:18.169513750 +0900
1185 @@ -1226,6 +1226,15 @@
1189 +/*************************************************************************
1190 +set is_corrupt flag by space_id*/
1193 +dict_table_set_corrupt_by_space(
1194 +/*============================*/
1196 + ibool need_mutex);
1199 #include "dict0dict.ic"
1201 diff -ruN a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
1202 --- a/storage/innobase/include/dict0mem.h 2010-11-03 07:01:13.000000000 +0900
1203 +++ b/storage/innobase/include/dict0mem.h 2010-12-04 15:38:18.171513956 +0900
1205 the AUTOINC lock on this table. */
1207 /*----------------------*/
1209 #endif /* !UNIV_HOTBACKUP */
1212 diff -ruN a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
1213 --- a/storage/innobase/include/fil0fil.h 2010-12-04 15:35:29.175520016 +0900
1214 +++ b/storage/innobase/include/fil0fil.h 2010-12-04 15:38:18.172483391 +0900
1215 @@ -749,6 +749,19 @@
1216 fil_system_hash_nodes(void);
1217 /*========================*/
1219 +/*************************************************************************
1220 +functions to access is_corrupt flag of fil_space_t*/
1223 +fil_space_is_corrupt(
1224 +/*=================*/
1228 +fil_space_set_corrupt(
1229 +/*==================*/
1232 typedef struct fil_space_struct fil_space_t;
1235 diff -ruN a/storage/innobase/include/fut0fut.ic b/storage/innobase/include/fut0fut.ic
1236 --- a/storage/innobase/include/fut0fut.ic 2010-11-03 07:01:13.000000000 +0900
1237 +++ b/storage/innobase/include/fut0fut.ic 2010-12-04 15:38:18.174481728 +0900
1239 Created 12/13/1995 Heikki Tuuri
1240 ***********************************************************************/
1242 +#include "srv0srv.h"
1243 #include "sync0rw.h"
1244 #include "buf0buf.h"
1247 ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
1249 block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr);
1251 + if (srv_pass_corrupt_table && !block) {
1256 ptr = buf_block_get_frame(block) + addr.boffset;
1258 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
1259 diff -ruN a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h
1260 --- a/storage/innobase/include/page0page.h 2010-11-03 07:01:13.000000000 +0900
1261 +++ b/storage/innobase/include/page0page.h 2010-12-04 15:38:18.175514037 +0900
1265 const page_t* page) /*!< in: page */
1266 - __attribute__((nonnull, pure));
1267 + __attribute__((pure));
1268 /************************************************************//**
1269 Gets the pointer to the next record on the page.
1270 @return pointer to next record */
1271 diff -ruN a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic
1272 --- a/storage/innobase/include/page0page.ic 2010-11-03 07:01:13.000000000 +0900
1273 +++ b/storage/innobase/include/page0page.ic 2010-12-04 15:38:18.177482672 +0900
1276 const page_t* page) /*!< in: page */
1281 return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
1284 diff -ruN a/storage/innobase/include/page0zip.h b/storage/innobase/include/page0zip.h
1285 --- a/storage/innobase/include/page0zip.h 2010-11-03 07:01:13.000000000 +0900
1286 +++ b/storage/innobase/include/page0zip.h 2010-12-04 15:38:18.179513974 +0900
1288 const page_t* page, /*!< in: uncompressed page */
1289 dict_index_t* index, /*!< in: index of the B-tree node */
1290 mtr_t* mtr) /*!< in: mini-transaction, or NULL */
1291 - __attribute__((nonnull(1,2,3)));
1292 + __attribute__((nonnull(1,3)));
1294 /**********************************************************************//**
1295 Decompress a page. This function should tolerate errors on the compressed
1296 diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
1297 --- a/storage/innobase/include/srv0srv.h 2010-12-04 15:37:50.591516341 +0900
1298 +++ b/storage/innobase/include/srv0srv.h 2010-12-04 15:38:18.180563749 +0900
1300 extern ulint srv_adaptive_flushing_method;
1302 extern ulint srv_expand_import;
1303 +extern ulint srv_pass_corrupt_table;
1305 extern ulint srv_extra_rsegments;
1306 extern ulint srv_dict_size_limit;
1307 diff -ruN a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c
1308 --- a/storage/innobase/page/page0zip.c 2010-11-03 07:01:13.000000000 +0900
1309 +++ b/storage/innobase/page/page0zip.c 2010-12-04 15:38:18.195515935 +0900
1310 @@ -1153,6 +1153,10 @@
1311 FILE* logfile = NULL;
1318 ut_a(page_is_comp(page));
1319 ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
1320 ut_ad(page_simple_validate_new((page_t*) page));
1321 diff -ruN a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
1322 --- a/storage/innobase/row/row0ins.c 2010-11-03 07:01:13.000000000 +0900
1323 +++ b/storage/innobase/row/row0ins.c 2010-12-04 15:38:18.198514028 +0900
1324 @@ -1335,6 +1335,12 @@
1325 const rec_t* rec = btr_pcur_get_rec(&pcur);
1326 const buf_block_t* block = btr_pcur_get_block(&pcur);
1328 + if (srv_pass_corrupt_table && !block) {
1329 + err = DB_CORRUPTION;
1334 if (page_rec_is_infimum(rec)) {
1337 diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
1338 --- a/storage/innobase/row/row0merge.c 2010-12-03 17:30:16.330986655 +0900
1339 +++ b/storage/innobase/row/row0merge.c 2010-12-04 15:38:18.201513966 +0900
1340 @@ -1245,6 +1245,13 @@
1342 if (UNIV_LIKELY(has_next)) {
1343 rec = btr_pcur_get_rec(&pcur);
1345 + if (srv_pass_corrupt_table && !rec) {
1346 + err = DB_CORRUPTION;
1351 offsets = rec_get_offsets(rec, clust_index, NULL,
1352 ULINT_UNDEFINED, &row_heap);
1354 diff -ruN a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
1355 --- a/storage/innobase/row/row0sel.c 2010-11-03 07:01:13.000000000 +0900
1356 +++ b/storage/innobase/row/row0sel.c 2010-12-04 15:38:18.205551115 +0900
1357 @@ -3848,6 +3848,13 @@
1358 /* PHASE 4: Look for matching records in a loop */
1360 rec = btr_pcur_get_rec(pcur);
1362 + if (srv_pass_corrupt_table && !rec) {
1363 + err = DB_CORRUPTION;
1364 + goto lock_wait_or_error;
1368 ut_ad(!!page_rec_is_comp(rec) == comp);
1369 #ifdef UNIV_SEARCH_DEBUG
1371 diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
1372 --- a/storage/innobase/srv/srv0srv.c 2010-12-04 15:37:50.602481253 +0900
1373 +++ b/storage/innobase/srv/srv0srv.c 2010-12-04 15:38:18.209513823 +0900
1375 UNIV_INTERN ulint srv_adaptive_flushing_method = 0; /* 0: native 1: estimate 2: keep_average */
1377 UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */
1378 +UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
1380 UNIV_INTERN ulint srv_extra_rsegments = 127; /* extra rseg for users */
1381 UNIV_INTERN ulint srv_dict_size_limit = 0;
1382 diff -ruN a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
1383 --- a/storage/innobase/srv/srv0start.c 2010-12-04 15:37:50.605491300 +0900
1384 +++ b/storage/innobase/srv/srv0start.c 2010-12-04 15:38:18.212513722 +0900
1385 @@ -2141,6 +2141,13 @@
1387 os_fast_mutex_free(&srv_os_test_mutex);
1389 + if (!srv_file_per_table_original_value
1390 + && srv_pass_corrupt_table) {
1391 + fprintf(stderr, "InnoDB: Warning:"
1392 + " The option innodb_file_per_table is disabled,"
1393 + " so using the option innodb_pass_corrupt_table doesn't make sense.\n");
1396 if (srv_print_verbose_log) {
1397 ut_print_timestamp(stderr);