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;
37 @@ -1433,6 +1445,13 @@
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
51 @@ -1455,6 +1474,12 @@
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
64 @@ -1488,6 +1513,11 @@
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 @@ -986,6 +1050,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 @@ -1199,6 +1271,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 @@ -2925,6 +3003,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 @@ -3628,6 +3711,11 @@
248 page = btr_cur_get_page(&cursor);
250 + if (srv_pass_corrupt_table && !page) {
255 rec = page_rec_get_next(page_get_infimum_rec(page));
257 if (!page_rec_is_supremum(rec)) {
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 @@ -1135,6 +1136,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 @@ -2479,6 +2485,13 @@
350 + if (srv_pass_corrupt_table <= 1) {
351 + if (bpage->is_corrupt) {
352 + rw_lock_s_unlock(&buf_pool->page_hash_latch);
357 block_mutex = buf_page_get_mutex_enter(bpage);
359 rw_lock_s_unlock(&buf_pool->page_hash_latch);
360 @@ -3059,6 +3072,13 @@
364 + if (srv_pass_corrupt_table <= 1) {
365 + if (block->page.is_corrupt) {
366 + mutex_exit(block_mutex);
371 switch (buf_block_get_state(block)) {
374 @@ -3733,6 +3753,7 @@
375 bpage->newest_modification = 0;
376 bpage->oldest_modification = 0;
377 HASH_INVALIDATE(bpage, hash);
378 + bpage->is_corrupt = FALSE;
379 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
380 bpage->file_page_was_freed = FALSE;
381 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
382 @@ -4322,6 +4343,7 @@
383 (ulong) bpage->offset);
386 + if (!srv_pass_corrupt_table || !bpage->is_corrupt) {
387 /* From version 3.23.38 up we store the page checksum
388 to the 4 first bytes of the page end lsn field */
390 @@ -4363,6 +4385,23 @@
391 REFMAN "forcing-innodb-recovery.html\n"
392 "InnoDB: about forcing recovery.\n", stderr);
394 + if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space)
395 + && bpage->space < SRV_LOG_SPACE_FIRST_ID) {
399 + "InnoDB: space %u will be treated as corrupt.\n",
401 + fil_space_set_corrupt(bpage->space);
403 + trx = innobase_get_trx();
404 + if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) {
405 + dict_table_set_corrupt_by_space(bpage->space, FALSE);
407 + dict_table_set_corrupt_by_space(bpage->space, TRUE);
409 + bpage->is_corrupt = TRUE;
411 if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
412 fputs("InnoDB: Ending processing because of"
413 " a corrupt database page.\n",
414 @@ -4370,6 +4409,7 @@
420 if (recv_recovery_is_on()) {
421 /* Pages must be uncompressed for crash recovery. */
422 @@ -4379,8 +4419,11 @@
424 if (uncompressed && !recv_no_ibuf_operations) {
425 ibuf_merge_or_delete_for_page(
426 + /* Delete possible entries, if bpage is_corrupt */
427 + (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
428 (buf_block_t*) bpage, bpage->space,
429 bpage->offset, buf_page_get_zip_size(bpage),
430 + (srv_pass_corrupt_table && bpage->is_corrupt) ? FALSE :
434 diff -ruN a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c
435 --- a/storage/innobase/buf/buf0rea.c 2010-12-04 15:37:50.557553380 +0900
436 +++ b/storage/innobase/buf/buf0rea.c 2010-12-04 15:41:09.784467585 +0900
438 ((buf_block_t*) bpage)->frame, bpage, trx);
442 + if (srv_pass_corrupt_table) {
443 + if (*err != DB_SUCCESS) {
444 + bpage->is_corrupt = TRUE;
447 ut_a(*err == DB_SUCCESS);
451 /* The i/o is already completed when we arrive from
452 diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
453 --- a/storage/innobase/dict/dict0dict.c 2010-12-03 17:30:16.248987063 +0900
454 +++ b/storage/innobase/dict/dict0dict.c 2010-12-04 15:45:23.808513973 +0900
456 #include "row0merge.h"
457 #include "m_ctype.h" /* my_isspace() */
458 #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
459 +#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
465 mutex_exit(&(dict_sys->mutex));
467 - if (table != NULL) {
468 + if (table != NULL && !table->is_corrupt) {
469 /* If table->ibd_file_missing == TRUE, this will
470 print an error message and return without doing
472 @@ -1293,7 +1294,7 @@
473 + dict_sys->size) > srv_dict_size_limit ) {
474 prev_table = UT_LIST_GET_PREV(table_LRU, table);
476 - if (table == self || table->n_mysql_handles_opened)
477 + if (table == self || table->n_mysql_handles_opened || table->is_corrupt)
480 cached_foreign_tables = 0;
481 @@ -4332,6 +4333,12 @@
482 heap = mem_heap_create(1000);
485 + if (table->is_corrupt) {
486 + ut_a(srv_pass_corrupt_table);
487 + mem_heap_free(heap);
491 size = btr_get_size(index, BTR_TOTAL_SIZE);
493 index->stat_index_size = size;
494 @@ -4479,6 +4486,12 @@
495 heap = mem_heap_create(1000);
498 + if (table->is_corrupt) {
499 + ut_a(srv_pass_corrupt_table);
500 + mem_heap_free(heap);
504 /*===========================================*/
506 dict_table_t* sys_stats;
507 @@ -4671,6 +4684,13 @@
508 || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
509 && dict_index_is_clust(index)))) {
512 + if (table->is_corrupt) {
513 + ut_a(srv_pass_corrupt_table);
514 + dict_table_stats_unlock(table, RW_X_LATCH);
518 size = btr_get_size(index, BTR_TOTAL_SIZE);
520 index->stat_index_size = size;
521 @@ -5467,4 +5487,42 @@
522 rw_lock_free(&dict_table_stats_latches[i]);
526 +/*************************************************************************
527 +set is_corrupt flag by space_id*/
530 +dict_table_set_corrupt_by_space(
531 +/*============================*/
535 + dict_table_t* table;
536 + ibool found = FALSE;
538 + ut_a(!trx_sys_sys_space(space_id) && space_id < SRV_LOG_SPACE_FIRST_ID);
541 + mutex_enter(&(dict_sys->mutex));
543 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
546 + if (table->space == space_id) {
547 + table->is_corrupt = TRUE;
551 + table = UT_LIST_GET_NEXT(table_LRU, table);
555 + mutex_exit(&(dict_sys->mutex));
558 + fprintf(stderr, "InnoDB: space to be marked as "
559 + "crashed was not found for id %lu.\n",
563 #endif /* !UNIV_HOTBACKUP */
564 diff -ruN a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c
565 --- a/storage/innobase/dict/dict0mem.c 2010-11-03 07:01:13.000000000 +0900
566 +++ b/storage/innobase/dict/dict0mem.c 2010-12-04 15:38:18.126549463 +0900
568 /* The number of transactions that are either waiting on the
569 AUTOINC lock or have been granted the lock. */
570 table->n_waiting_or_granted_auto_inc_locks = 0;
572 + table->is_corrupt = FALSE;
573 #endif /* !UNIV_HOTBACKUP */
575 ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
576 diff -ruN a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
577 --- a/storage/innobase/fil/fil0fil.c 2010-12-04 15:37:50.564551587 +0900
578 +++ b/storage/innobase/fil/fil0fil.c 2010-12-04 15:38:18.128549252 +0900
580 file we have written to */
581 ibool is_in_unflushed_spaces; /*!< TRUE if this space is
582 currently in unflushed_spaces */
584 UT_LIST_NODE_T(fil_space_t) space_list;
585 /*!< list of all spaces */
586 ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
587 @@ -1293,6 +1294,8 @@
588 ut_fold_string(name), space);
589 space->is_in_unflushed_spaces = FALSE;
591 + space->is_corrupt = FALSE;
593 UT_LIST_ADD_LAST(space_list, fil_system->space_list, space);
595 mutex_exit(&fil_system->mutex);
596 @@ -5267,6 +5270,34 @@
597 ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
598 ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
600 + if (srv_pass_corrupt_table == 1 && space->is_corrupt) {
601 + /* should ignore i/o for the crashed space */
602 + mutex_enter(&fil_system->mutex);
603 + fil_node_complete_io(node, fil_system, type);
604 + mutex_exit(&fil_system->mutex);
605 + if (mode == OS_AIO_NORMAL) {
606 + ut_a(space->purpose == FIL_TABLESPACE);
607 + buf_page_io_complete(message);
609 + if (type == OS_FILE_READ) {
610 + return(DB_TABLESPACE_DELETED);
612 + return(DB_SUCCESS);
615 + if (srv_pass_corrupt_table > 1 && space->is_corrupt) {
616 + /* should ignore write i/o for the crashed space */
617 + if (type == OS_FILE_WRITE) {
618 + mutex_enter(&fil_system->mutex);
619 + fil_node_complete_io(node, fil_system, type);
620 + mutex_exit(&fil_system->mutex);
621 + if (mode == OS_AIO_NORMAL) {
622 + ut_a(space->purpose == FIL_TABLESPACE);
623 + buf_page_io_complete(message);
625 + return(DB_SUCCESS);
628 #ifdef UNIV_HOTBACKUP
629 /* In ibbackup do normal i/o, not aio */
630 if (type == OS_FILE_READ) {
631 @@ -5281,6 +5312,8 @@
632 ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
633 offset_low, offset_high, len, node, message, trx);
639 if (mode == OS_AIO_SYNC) {
640 @@ -5781,3 +5814,46 @@
645 +/*************************************************************************
646 +functions to access is_corrupt flag of fil_space_t*/
649 +fil_space_is_corrupt(
650 +/*=================*/
653 + fil_space_t* space;
656 + mutex_enter(&fil_system->mutex);
658 + space = fil_space_get_by_id(space_id);
660 + if (space && space->is_corrupt) {
664 + mutex_exit(&fil_system->mutex);
670 +fil_space_set_corrupt(
671 +/*==================*/
674 + fil_space_t* space;
676 + mutex_enter(&fil_system->mutex);
678 + space = fil_space_get_by_id(space_id);
681 + space->is_corrupt = TRUE;
684 + mutex_exit(&fil_system->mutex);
687 diff -ruN a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c
688 --- a/storage/innobase/fsp/fsp0fsp.c 2010-12-04 15:37:50.569480615 +0900
689 +++ b/storage/innobase/fsp/fsp0fsp.c 2010-12-04 15:38:18.131550103 +0900
691 ut_ad(id || !zip_size);
693 block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
695 + if (srv_pass_corrupt_table && !block) {
700 header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
701 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
704 fsp_header_t* sp_header;
706 block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
708 + if (srv_pass_corrupt_table && !block) {
713 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
715 sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
716 @@ -1866,6 +1878,11 @@
720 + if (srv_pass_corrupt_table && !page) {
721 + return(ULINT_UNDEFINED);
725 for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
727 inode = fsp_seg_inode_page_get_nth_inode(
728 @@ -1979,6 +1996,11 @@
730 page = buf_block_get_frame(block);
732 + if (srv_pass_corrupt_table && !page) {
737 n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
739 ut_a(n != ULINT_UNDEFINED);
740 @@ -2072,6 +2094,11 @@
742 inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
744 + if (srv_pass_corrupt_table && !inode) {
749 if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
752 @@ -2098,7 +2125,7 @@
755 = fseg_inode_try_get(header, space, zip_size, mtr);
757 + ut_a(srv_pass_corrupt_table || inode);
761 @@ -3304,6 +3331,11 @@
763 descr = xdes_get_descriptor(space, zip_size, page, mtr);
765 + if (srv_pass_corrupt_table && !descr) {
766 + /* The page may be corrupt. pass it. */
771 if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
772 fputs("InnoDB: Dump of the tablespace extent descriptor: ",
773 @@ -3551,6 +3583,11 @@
775 descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
777 + if (srv_pass_corrupt_table && !descr) {
778 + /* The page may be corrupt. pass it. */
782 /* Check that the header resides on a page which has not been
785 @@ -3635,6 +3672,12 @@
787 inode = fseg_inode_get(header, space, zip_size, mtr);
789 + if (srv_pass_corrupt_table && !inode) {
790 + /* ignore the corruption */
795 descr = fseg_get_first_extent(inode, space, zip_size, mtr);
798 diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
799 --- a/storage/innobase/handler/ha_innodb.cc 2010-12-04 15:37:50.578486593 +0900
800 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-04 15:38:18.137549396 +0900
801 @@ -3972,6 +3972,12 @@
805 + if (srv_pass_corrupt_table <= 1 && share->ib_table && share->ib_table->is_corrupt) {
808 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
811 /* Create buffers for packing the fields of a record. Why
812 table->reclength did not work here? Obviously, because char
813 fields when packed actually became 1 byte longer, when we also
814 @@ -3999,6 +4005,19 @@
815 /* Get pointer to a table object in InnoDB dictionary cache */
816 ib_table = dict_table_get(norm_name, TRUE);
818 + if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) {
822 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
825 + if (share->ib_table) {
826 + ut_a(share->ib_table == ib_table);
828 + share->ib_table = ib_table;
831 if (NULL == ib_table) {
832 if (is_part && retries < 10) {
834 @@ -5163,6 +5182,10 @@
836 ha_statistic_increment(&SSV::ha_write_count);
838 + if (share->ib_table->is_corrupt) {
839 + DBUG_RETURN(HA_ERR_CRASHED);
842 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
843 table->timestamp_field->set_time();
845 @@ -5380,6 +5403,10 @@
847 innobase_active_small();
849 + if (share->ib_table->is_corrupt) {
850 + DBUG_RETURN(HA_ERR_CRASHED);
853 DBUG_RETURN(error_result);
856 @@ -5556,6 +5583,10 @@
858 ha_statistic_increment(&SSV::ha_update_count);
860 + if (share->ib_table->is_corrupt) {
861 + DBUG_RETURN(HA_ERR_CRASHED);
864 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
865 table->timestamp_field->set_time();
867 @@ -5645,6 +5676,10 @@
869 innobase_active_small();
871 + if (share->ib_table->is_corrupt) {
872 + DBUG_RETURN(HA_ERR_CRASHED);
878 @@ -5666,6 +5701,10 @@
880 ha_statistic_increment(&SSV::ha_delete_count);
882 + if (share->ib_table->is_corrupt) {
883 + DBUG_RETURN(HA_ERR_CRASHED);
886 if (!prebuilt->upd_node) {
887 row_get_prebuilt_update_vector(prebuilt);
889 @@ -5692,6 +5731,10 @@
891 innobase_active_small();
893 + if (share->ib_table->is_corrupt) {
894 + DBUG_RETURN(HA_ERR_CRASHED);
900 @@ -5931,6 +5974,10 @@
902 ha_statistic_increment(&SSV::ha_read_key_count);
904 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
905 + DBUG_RETURN(HA_ERR_CRASHED);
908 index = prebuilt->index;
910 if (UNIV_UNLIKELY(index == NULL)) {
911 @@ -5996,6 +6043,10 @@
912 ret = DB_UNSUPPORTED;
915 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
916 + DBUG_RETURN(HA_ERR_CRASHED);
922 @@ -6111,6 +6162,10 @@
924 DBUG_ENTER("change_active_index");
926 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
927 + DBUG_RETURN(HA_ERR_CRASHED);
930 ut_ad(user_thd == ha_thd());
931 ut_a(prebuilt->trx == thd_to_trx(user_thd));
933 @@ -6201,6 +6256,10 @@
935 DBUG_ENTER("general_fetch");
937 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
938 + DBUG_RETURN(HA_ERR_CRASHED);
941 ut_a(prebuilt->trx == thd_to_trx(user_thd));
943 innodb_srv_conc_enter_innodb(prebuilt->trx);
944 @@ -6210,6 +6269,10 @@
946 innodb_srv_conc_exit_innodb(prebuilt->trx);
948 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
949 + DBUG_RETURN(HA_ERR_CRASHED);
955 @@ -7476,10 +7539,18 @@
957 update_thd(ha_thd());
959 + if (share->ib_table->is_corrupt) {
960 + DBUG_RETURN(HA_ERR_CRASHED);
963 /* Truncate the table in InnoDB */
965 error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
967 + if (share->ib_table->is_corrupt) {
968 + DBUG_RETURN(HA_ERR_CRASHED);
971 error = convert_error_code_to_mysql(error, prebuilt->table->flags,
974 @@ -7980,6 +8051,16 @@
975 return(ranges + (double) rows / (double) total_rows * time_for_scan);
980 +ha_innobase::is_corrupt() const
982 + if (share->ib_table)
983 + return ((bool)share->ib_table->is_corrupt);
988 /*********************************************************************//**
989 Calculates the key number used inside MySQL for an Innobase index. We will
990 first check the "index translation table" for a match of the index to get
991 @@ -8157,7 +8238,7 @@
992 ib_table = prebuilt->table;
994 if (flag & HA_STATUS_TIME) {
995 - if (called_from_analyze || innobase_stats_on_metadata) {
996 + if ((called_from_analyze || innobase_stats_on_metadata) && !share->ib_table->is_corrupt) {
997 /* In sql_show we call with this flag: update
998 then statistics so that they are up-to-date */
1000 @@ -8450,10 +8531,18 @@
1001 THD* thd, /*!< in: connection thread handle */
1002 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
1004 + if (share->ib_table->is_corrupt) {
1005 + return(HA_ADMIN_CORRUPT);
1008 /* Simply call ::info() with all the flags */
1009 info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
1010 true /* called from analyze */);
1012 + if (share->ib_table->is_corrupt) {
1013 + return(HA_ADMIN_CORRUPT);
1019 @@ -8635,6 +8724,10 @@
1020 my_error(ER_QUERY_INTERRUPTED, MYF(0));
1023 + if (share->ib_table->is_corrupt) {
1024 + return(HA_ADMIN_CORRUPT);
1027 DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
1030 @@ -9405,6 +9498,10 @@
1034 + if (share->ib_table->is_corrupt) {
1035 + DBUG_RETURN(HA_ERR_CRASHED);
1038 if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) {
1039 ut_print_timestamp(stderr);
1041 @@ -11807,6 +11904,26 @@
1042 "0 (the default) disables automatic dumps.",
1043 NULL, NULL, 0, 0, UINT_MAX32, 0);
1045 +const char *corrupt_table_action_names[]=
1049 + "salvage", /* 2 */
1052 +TYPELIB corrupt_table_action_typelib=
1054 + array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib",
1055 + corrupt_table_action_names, NULL
1057 +static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
1058 + PLUGIN_VAR_RQCMDARG,
1059 + "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, "
1060 + "when used with file_per_table. "
1061 + "All file io for the datafile after detected as corrupt are disabled, "
1062 + "except for the deletion.",
1063 + NULL, NULL, 0, &corrupt_table_action_typelib);
1065 static struct st_mysql_sys_var* innobase_system_variables[]= {
1066 MYSQL_SYSVAR(additional_mem_pool_size),
1067 MYSQL_SYSVAR(autoextend_increment),
1068 @@ -11893,6 +12010,7 @@
1069 MYSQL_SYSVAR(purge_threads),
1070 MYSQL_SYSVAR(purge_batch_size),
1071 MYSQL_SYSVAR(rollback_segments),
1072 + MYSQL_SYSVAR(corrupt_table_action),
1076 diff -ruN a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
1077 --- a/storage/innobase/handler/ha_innodb.h 2010-11-03 07:01:13.000000000 +0900
1078 +++ b/storage/innobase/handler/ha_innodb.h 2010-12-04 15:38:18.159588579 +0900
1080 innodb_idx_translate_t idx_trans_tbl; /*!< index translation
1081 table between MySQL and
1083 + dict_table_t* ib_table;
1090 double read_time(uint index, uint ranges, ha_rows rows);
1091 + bool is_corrupt() const;
1093 int write_row(uchar * buf);
1094 int update_row(const uchar * old_data, uchar * new_data);
1095 diff -ruN a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic
1096 --- a/storage/innobase/include/btr0btr.ic 2010-11-03 07:01:13.000000000 +0900
1097 +++ b/storage/innobase/include/btr0btr.ic 2010-12-04 15:38:18.162515035 +0900
1099 #include "mtr0mtr.h"
1100 #include "mtr0log.h"
1101 #include "page0zip.h"
1103 +#include "srv0srv.h"
1104 #define BTR_MAX_NODE_LEVEL 50 /*!< Maximum B-tree page level
1105 (not really a hard limit).
1106 Used in debug assertions
1108 block = buf_page_get_gen(space, zip_size, page_no, mode,
1109 NULL, BUF_GET, file, line, mtr);
1111 - if (mode != RW_NO_LATCH) {
1112 + ut_a(srv_pass_corrupt_table || block);
1114 + if (block && mode != RW_NO_LATCH) {
1116 buf_block_dbg_add_level(block, SYNC_TREE_NODE);
1118 diff -ruN a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
1119 --- a/storage/innobase/include/buf0buf.h 2010-12-03 15:49:59.218956083 +0900
1120 +++ b/storage/innobase/include/buf0buf.h 2010-12-04 15:38:18.164513667 +0900
1122 const buf_block_t* block) /*!< in: pointer to the control block */
1123 __attribute__((pure));
1124 #else /* UNIV_DEBUG */
1125 -# define buf_block_get_frame(block) (block)->frame
1126 +# define buf_block_get_frame(block) (block ? (block)->frame : 0)
1127 #endif /* UNIV_DEBUG */
1128 /*********************************************************************//**
1129 Gets the space id of a block.
1130 @@ -1433,6 +1433,7 @@
1131 0 if the block was never accessed
1132 in the buffer pool */
1135 # if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1136 ibool file_page_was_freed;
1137 /*!< this is set to TRUE when fsp
1138 diff -ruN a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
1139 --- a/storage/innobase/include/buf0buf.ic 2010-12-03 15:49:59.221956024 +0900
1140 +++ b/storage/innobase/include/buf0buf.ic 2010-12-04 15:38:18.167513925 +0900
1142 #include "buf0flu.h"
1143 #include "buf0lru.h"
1144 #include "buf0rea.h"
1146 +#include "srv0srv.h"
1147 /*********************************************************************//**
1148 Gets the current size of buffer buf_pool in bytes.
1149 @return size in bytes */
1150 @@ -619,6 +619,12 @@
1151 /*================*/
1152 const buf_block_t* block) /*!< in: pointer to the control block */
1154 + ut_a(srv_pass_corrupt_table || block);
1156 + if (srv_pass_corrupt_table && !block) {
1162 switch (buf_block_get_state(block)) {
1163 diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
1164 --- a/storage/innobase/include/dict0dict.h 2010-12-03 17:30:16.306955940 +0900
1165 +++ b/storage/innobase/include/dict0dict.h 2010-12-04 15:38:18.169513750 +0900
1166 @@ -1245,6 +1245,15 @@
1170 +/*************************************************************************
1171 +set is_corrupt flag by space_id*/
1174 +dict_table_set_corrupt_by_space(
1175 +/*============================*/
1177 + ibool need_mutex);
1180 #include "dict0dict.ic"
1182 diff -ruN a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
1183 --- a/storage/innobase/include/dict0mem.h 2010-11-03 07:01:13.000000000 +0900
1184 +++ b/storage/innobase/include/dict0mem.h 2010-12-04 15:38:18.171513956 +0900
1186 the AUTOINC lock on this table. */
1188 /*----------------------*/
1190 #endif /* !UNIV_HOTBACKUP */
1193 diff -ruN a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
1194 --- a/storage/innobase/include/fil0fil.h 2010-12-04 15:35:29.175520016 +0900
1195 +++ b/storage/innobase/include/fil0fil.h 2010-12-04 15:38:18.172483391 +0900
1196 @@ -750,6 +750,19 @@
1197 fil_system_hash_nodes(void);
1198 /*========================*/
1200 +/*************************************************************************
1201 +functions to access is_corrupt flag of fil_space_t*/
1204 +fil_space_is_corrupt(
1205 +/*=================*/
1209 +fil_space_set_corrupt(
1210 +/*==================*/
1213 typedef struct fil_space_struct fil_space_t;
1216 diff -ruN a/storage/innobase/include/fut0fut.ic b/storage/innobase/include/fut0fut.ic
1217 --- a/storage/innobase/include/fut0fut.ic 2010-11-03 07:01:13.000000000 +0900
1218 +++ b/storage/innobase/include/fut0fut.ic 2010-12-04 15:38:18.174481728 +0900
1220 Created 12/13/1995 Heikki Tuuri
1221 ***********************************************************************/
1223 +#include "srv0srv.h"
1224 #include "sync0rw.h"
1225 #include "buf0buf.h"
1228 ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
1230 block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr);
1232 + if (srv_pass_corrupt_table && !block) {
1237 ptr = buf_block_get_frame(block) + addr.boffset;
1239 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
1240 diff -ruN a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h
1241 --- a/storage/innobase/include/page0page.h 2010-11-03 07:01:13.000000000 +0900
1242 +++ b/storage/innobase/include/page0page.h 2010-12-04 15:38:18.175514037 +0900
1246 const page_t* page) /*!< in: page */
1247 - __attribute__((nonnull, pure));
1248 + __attribute__((pure));
1249 /************************************************************//**
1250 Gets the pointer to the next record on the page.
1251 @return pointer to next record */
1252 diff -ruN a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic
1253 --- a/storage/innobase/include/page0page.ic 2010-11-03 07:01:13.000000000 +0900
1254 +++ b/storage/innobase/include/page0page.ic 2010-12-04 15:38:18.177482672 +0900
1257 const page_t* page) /*!< in: page */
1262 return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
1265 diff -ruN a/storage/innobase/include/page0zip.h b/storage/innobase/include/page0zip.h
1266 --- a/storage/innobase/include/page0zip.h 2010-11-03 07:01:13.000000000 +0900
1267 +++ b/storage/innobase/include/page0zip.h 2010-12-04 15:38:18.179513974 +0900
1269 const page_t* page, /*!< in: uncompressed page */
1270 dict_index_t* index, /*!< in: index of the B-tree node */
1271 mtr_t* mtr) /*!< in: mini-transaction, or NULL */
1272 - __attribute__((nonnull(1,2,3)));
1273 + __attribute__((nonnull(1,3)));
1275 /**********************************************************************//**
1276 Decompress a page. This function should tolerate errors on the compressed
1277 diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
1278 --- a/storage/innobase/include/srv0srv.h 2010-12-04 15:37:50.591516341 +0900
1279 +++ b/storage/innobase/include/srv0srv.h 2010-12-04 15:38:18.180563749 +0900
1281 extern ulint srv_adaptive_flushing_method;
1283 extern ulint srv_expand_import;
1284 +extern ulint srv_pass_corrupt_table;
1286 extern ulint srv_dict_size_limit;
1287 /*-------------------------------------------*/
1288 diff -ruN a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c
1289 --- a/storage/innobase/page/page0zip.c 2010-11-03 07:01:13.000000000 +0900
1290 +++ b/storage/innobase/page/page0zip.c 2010-12-04 15:38:18.195515935 +0900
1291 @@ -1153,6 +1153,10 @@
1292 FILE* logfile = NULL;
1299 ut_a(page_is_comp(page));
1300 ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
1301 ut_ad(page_simple_validate_new((page_t*) page));
1302 diff -ruN a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
1303 --- a/storage/innobase/row/row0ins.c 2010-11-03 07:01:13.000000000 +0900
1304 +++ b/storage/innobase/row/row0ins.c 2010-12-04 15:38:18.198514028 +0900
1305 @@ -1335,6 +1335,12 @@
1306 const rec_t* rec = btr_pcur_get_rec(&pcur);
1307 const buf_block_t* block = btr_pcur_get_block(&pcur);
1309 + if (srv_pass_corrupt_table && !block) {
1310 + err = DB_CORRUPTION;
1315 if (page_rec_is_infimum(rec)) {
1318 diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
1319 --- a/storage/innobase/row/row0merge.c 2010-12-03 17:30:16.330986655 +0900
1320 +++ b/storage/innobase/row/row0merge.c 2010-12-04 15:38:18.201513966 +0900
1321 @@ -1245,6 +1245,13 @@
1323 if (UNIV_LIKELY(has_next)) {
1324 rec = btr_pcur_get_rec(&pcur);
1326 + if (srv_pass_corrupt_table && !rec) {
1327 + err = DB_CORRUPTION;
1332 offsets = rec_get_offsets(rec, clust_index, NULL,
1333 ULINT_UNDEFINED, &row_heap);
1335 diff -ruN a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
1336 --- a/storage/innobase/row/row0sel.c 2010-11-03 07:01:13.000000000 +0900
1337 +++ b/storage/innobase/row/row0sel.c 2010-12-04 15:38:18.205551115 +0900
1338 @@ -3853,6 +3853,13 @@
1339 /* PHASE 4: Look for matching records in a loop */
1341 rec = btr_pcur_get_rec(pcur);
1343 + if (srv_pass_corrupt_table && !rec) {
1344 + err = DB_CORRUPTION;
1345 + goto lock_wait_or_error;
1349 ut_ad(!!page_rec_is_comp(rec) == comp);
1350 #ifdef UNIV_SEARCH_DEBUG
1352 @@ -3930,7 +3937,13 @@
1353 if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
1356 - if (srv_force_recovery == 0 || moves_up == FALSE) {
1357 + if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
1358 + index->table->is_corrupt = TRUE;
1359 + fil_space_set_corrupt(index->table->space);
1362 + if ((srv_force_recovery == 0 || moves_up == FALSE)
1363 + && srv_pass_corrupt_table <= 1) {
1364 ut_print_timestamp(stderr);
1365 buf_page_print(page_align(rec), 0);
1367 @@ -3981,7 +3994,8 @@
1369 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
1371 - if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
1372 + if (UNIV_UNLIKELY(srv_force_recovery > 0)
1373 + || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) {
1374 if (!rec_validate(rec, offsets)
1375 || !btr_index_rec_validate(rec, index, FALSE)) {
1377 diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
1378 --- a/storage/innobase/srv/srv0srv.c 2010-12-04 15:37:50.602481253 +0900
1379 +++ b/storage/innobase/srv/srv0srv.c 2010-12-04 15:38:18.209513823 +0900
1381 UNIV_INTERN ulint srv_adaptive_flushing_method = 0; /* 0: native 1: estimate 2: keep_average */
1383 UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */
1384 +UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
1386 UNIV_INTERN ulint srv_dict_size_limit = 0;
1387 /*-------------------------------------------*/
1388 diff -ruN a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
1389 --- a/storage/innobase/srv/srv0start.c 2010-12-04 15:37:50.605491300 +0900
1390 +++ b/storage/innobase/srv/srv0start.c 2010-12-04 15:38:18.212513722 +0900
1391 @@ -2149,6 +2149,13 @@
1393 os_fast_mutex_free(&srv_os_test_mutex);
1395 + if (!srv_file_per_table_original_value
1396 + && srv_pass_corrupt_table) {
1397 + fprintf(stderr, "InnoDB: Warning:"
1398 + " The option innodb_file_per_table is disabled,"
1399 + " so using the option innodb_pass_corrupt_table doesn't make sense.\n");
1402 if (srv_print_verbose_log) {
1403 ut_print_timestamp(stderr);