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 --- a/storage/innodb_plugin/btr/btr0btr.c
9 +++ b/storage/innodb_plugin/btr/btr0btr.c
11 root_page_no = dict_index_get_page(index);
13 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
15 + if (srv_pass_corrupt_table && !block) {
20 ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
21 == dict_table_is_comp(index->table));
25 root = btr_root_get(index, &mtr);
27 + if (srv_pass_corrupt_table && !root) {
33 if (flag == BTR_N_LEAF_PAGES) {
34 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
36 @@ -1431,6 +1443,13 @@
39 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
41 + if (srv_pass_corrupt_table && !root) {
48 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
50 @@ -1453,6 +1472,12 @@
53 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
55 + if (srv_pass_corrupt_table && !root) {
61 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
63 @@ -1486,6 +1511,11 @@
65 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
67 + if (srv_pass_corrupt_table && !block) {
72 btr_search_drop_page_hash_index(block);
74 header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP;
75 --- a/storage/innodb_plugin/btr/btr0cur.c
76 +++ b/storage/innodb_plugin/btr/btr0cur.c
79 mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH;
80 get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
82 + if (srv_pass_corrupt_table && !get_block) {
87 ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
88 #endif /* UNIV_BTR_DEBUG */
90 get_block = btr_block_get(space, zip_size,
94 + if (srv_pass_corrupt_table && !get_block) {
99 ut_a(page_is_comp(get_block->frame)
100 == page_is_comp(page));
103 get_block = btr_block_get(space, zip_size, page_no,
106 + if (srv_pass_corrupt_table && !get_block) {
110 #ifdef UNIV_BTR_DEBUG
111 ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
112 #endif /* UNIV_BTR_DEBUG */
114 get_block = btr_block_get(space, zip_size,
118 + if (srv_pass_corrupt_table && !get_block) {
122 #ifdef UNIV_BTR_DEBUG
123 ut_a(page_is_comp(get_block->frame)
124 == page_is_comp(page));
126 get_block = btr_block_get(space, zip_size,
127 left_page_no, mode, mtr);
128 cursor->left_block = get_block;
130 + if (srv_pass_corrupt_table && !get_block) {
134 #ifdef UNIV_BTR_DEBUG
135 ut_a(page_is_comp(get_block->frame)
136 == page_is_comp(page));
140 get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
142 + if (srv_pass_corrupt_table && !get_block) {
146 #ifdef UNIV_BTR_DEBUG
147 ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
148 #endif /* UNIV_BTR_DEBUG */
150 rw_latch, guess, buf_mode,
153 + if (srv_pass_corrupt_table && buf_mode != BUF_GET_IF_IN_POOL) {
154 + page_cursor->block = 0;
155 + page_cursor->rec = 0;
157 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
161 + ut_a(buf_mode == BUF_GET_IF_IN_POOL);
163 /* This must be a search to perform an insert;
164 try insert to the insert buffer */
168 page = buf_block_get_frame(block);
170 + if (srv_pass_corrupt_table && !page) {
171 + page_cursor->block = 0;
172 + page_cursor->rec = 0;
174 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
180 block->check_index_page_at_flush = TRUE;
182 if (rw_latch != RW_NO_LATCH) {
184 RW_NO_LATCH, NULL, BUF_GET,
186 page = buf_block_get_frame(block);
188 + if (srv_pass_corrupt_table && !page) {
189 + page_cursor->block = 0;
190 + page_cursor->rec = 0;
192 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
198 ut_ad(0 == ut_dulint_cmp(index->id,
199 btr_page_get_index_id(page)));
202 RW_NO_LATCH, NULL, BUF_GET,
204 page = buf_block_get_frame(block);
206 + if (srv_pass_corrupt_table && !page) {
207 + page_cursor->block = 0;
208 + page_cursor->rec = 0;
213 ut_ad(0 == ut_dulint_cmp(index->id,
214 btr_page_get_index_id(page)));
216 @@ -1081,6 +1150,12 @@
219 block = btr_cur_get_block(cursor);
221 + if (srv_pass_corrupt_table && !block) {
222 + return(DB_CORRUPTION);
226 page = buf_block_get_frame(block);
227 index = cursor->index;
228 zip_size = buf_block_get_zip_size(block);
229 @@ -2869,6 +2944,11 @@
231 block = btr_cur_get_block(cursor);
233 + if (srv_pass_corrupt_table && !block) {
234 + return(DB_CORRUPTION);
238 ut_ad(page_is_leaf(buf_block_get_frame(block)));
240 rec = btr_cur_get_rec(cursor);
241 @@ -3413,6 +3493,11 @@
243 page = btr_cur_get_page(&cursor);
245 + if (srv_pass_corrupt_table && !page) {
250 rec = page_rec_get_next(page_get_infimum_rec(page));
252 if (!page_rec_is_supremum(rec)) {
253 --- a/storage/innodb_plugin/btr/btr0pcur.c
254 +++ b/storage/innodb_plugin/btr/btr0pcur.c
260 +#include "srv0srv.h"
261 /**************************************************************//**
262 Allocates memory for a persistent cursor object and initializes the cursor.
263 @return own: persistent cursor */
265 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
267 block = btr_pcur_get_block(cursor);
269 + if (srv_pass_corrupt_table && !block) {
274 index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
276 page_cursor = btr_pcur_get_page_cur(cursor);
278 next_block = btr_block_get(space, zip_size, next_page_no,
279 cursor->latch_mode, mtr);
280 next_page = buf_block_get_frame(next_block);
282 + if (srv_pass_corrupt_table && !next_page) {
283 + btr_leaf_page_release(btr_pcur_get_block(cursor),
284 + cursor->latch_mode, mtr);
285 + btr_pcur_get_page_cur(cursor)->block = 0;
286 + btr_pcur_get_page_cur(cursor)->rec = 0;
290 #ifdef UNIV_BTR_DEBUG
291 ut_a(page_is_comp(next_page) == page_is_comp(page));
292 ut_a(btr_page_get_prev(next_page, mtr)
293 --- a/storage/innodb_plugin/btr/btr0sea.c
294 +++ b/storage/innodb_plugin/btr/btr0sea.c
296 #include "btr0pcur.h"
300 +#include "srv0srv.h"
301 /** Flag: has the search system been enabled?
302 Protected by btr_search_latch and btr_search_enabled_mutex. */
303 UNIV_INTERN char btr_search_enabled = TRUE;
306 block = btr_cur_get_block(cursor);
308 + if (srv_pass_corrupt_table && !block) {
313 /* NOTE that the following two function calls do NOT protect
314 info or block->n_fields etc. with any semaphore, to save CPU time!
315 We cannot assume the fields are consistent when we return from
316 --- a/storage/innodb_plugin/buf/buf0buf.c
317 +++ b/storage/innodb_plugin/buf/buf0buf.c
319 #include "log0recv.h"
320 #include "page0zip.h"
322 +#include "srv0start.h"
324 /* prototypes for new functions added to ha_innodb.cc */
325 trx_t* innobase_get_trx();
327 ready = buf_flush_ready_for_replace(&block->page);
328 mutex_exit(&block->mutex);
330 + if (block->page.is_corrupt) {
331 + /* corrupt page may remain, it can be skipped */
338 @@ -1420,6 +1426,13 @@
342 + if (srv_pass_corrupt_table <= 1) {
343 + if (bpage->is_corrupt) {
344 + rw_lock_s_unlock(&page_hash_latch);
349 block_mutex = buf_page_get_mutex_enter(bpage);
351 rw_lock_s_unlock(&page_hash_latch);
352 @@ -1909,6 +1922,13 @@
356 + if (srv_pass_corrupt_table <= 1) {
357 + if (block->page.is_corrupt) {
358 + mutex_exit(block_mutex);
363 switch (buf_block_get_state(block)) {
366 @@ -2557,6 +2577,7 @@
367 bpage->newest_modification = 0;
368 bpage->oldest_modification = 0;
369 HASH_INVALIDATE(bpage, hash);
370 + bpage->is_corrupt = FALSE;
371 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
372 bpage->file_page_was_freed = FALSE;
373 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
374 @@ -3087,6 +3108,7 @@
375 (ulong) bpage->offset);
378 + if (!srv_pass_corrupt_table || !bpage->is_corrupt) {
379 /* From version 3.23.38 up we store the page checksum
380 to the 4 first bytes of the page end lsn field */
382 @@ -3128,6 +3150,23 @@
383 REFMAN "forcing-innodb-recovery.html\n"
384 "InnoDB: about forcing recovery.\n", stderr);
386 + if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space)
387 + && bpage->space < SRV_LOG_SPACE_FIRST_ID) {
391 + "InnoDB: space %u will be treated as corrupt.\n",
393 + fil_space_set_corrupt(bpage->space);
395 + trx = innobase_get_trx();
396 + if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) {
397 + dict_table_set_corrupt_by_space(bpage->space, FALSE);
399 + dict_table_set_corrupt_by_space(bpage->space, TRUE);
401 + bpage->is_corrupt = TRUE;
403 if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
404 fputs("InnoDB: Ending processing because of"
405 " a corrupt database page.\n",
406 @@ -3135,6 +3174,7 @@
412 if (recv_recovery_is_on()) {
413 /* Pages must be uncompressed for crash recovery. */
414 @@ -3144,8 +3184,11 @@
416 if (uncompressed && !recv_no_ibuf_operations) {
417 ibuf_merge_or_delete_for_page(
418 + /* Delete possible entries, if bpage is_corrupt */
419 + (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
420 (buf_block_t*) bpage, bpage->space,
421 bpage->offset, buf_page_get_zip_size(bpage),
422 + (srv_pass_corrupt_table && bpage->is_corrupt) ? FALSE :
426 --- a/storage/innodb_plugin/buf/buf0rea.c
427 +++ b/storage/innodb_plugin/buf/buf0rea.c
429 sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
430 ((buf_block_t*) bpage)->frame, bpage, trx);
433 + if (srv_pass_corrupt_table) {
434 + if (*err != DB_SUCCESS) {
435 + bpage->is_corrupt = TRUE;
438 ut_a(*err == DB_SUCCESS);
442 /* The i/o is already completed when we arrive from
443 --- a/storage/innodb_plugin/dict/dict0dict.c
444 +++ b/storage/innodb_plugin/dict/dict0dict.c
446 #include "row0merge.h"
447 #include "m_ctype.h" /* my_isspace() */
448 #include "ha_prototypes.h" /* innobase_strcasecmp() */
449 +#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
455 mutex_exit(&(dict_sys->mutex));
457 - if (table != NULL) {
458 + if (table != NULL && !table->is_corrupt) {
459 /* If table->ibd_file_missing == TRUE, this will
460 print an error message and return without doing
462 @@ -1275,7 +1276,7 @@
463 + dict_sys->size) > srv_dict_size_limit ) {
464 prev_table = UT_LIST_GET_PREV(table_LRU, table);
466 - if (table == self || table->n_mysql_handles_opened)
467 + if (table == self || table->n_mysql_handles_opened || table->is_corrupt)
470 cached_foreign_tables = 0;
471 @@ -4328,6 +4329,12 @@
475 + if (table->is_corrupt) {
476 + ut_a(srv_pass_corrupt_table);
477 + dict_table_stats_unlock(table, RW_X_LATCH);
482 (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
483 || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
484 @@ -5054,4 +5061,42 @@
485 rw_lock_free(&dict_table_stats_latches[i]);
489 +/*************************************************************************
490 +set is_corrupt flag by space_id*/
493 +dict_table_set_corrupt_by_space(
494 +/*============================*/
498 + dict_table_t* table;
499 + ibool found = FALSE;
501 + ut_a(!trx_sys_sys_space(space_id) && space_id < SRV_LOG_SPACE_FIRST_ID);
504 + mutex_enter(&(dict_sys->mutex));
506 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
509 + if (table->space == space_id) {
510 + table->is_corrupt = TRUE;
514 + table = UT_LIST_GET_NEXT(table_LRU, table);
518 + mutex_exit(&(dict_sys->mutex));
521 + fprintf(stderr, "InnoDB: space to be marked as "
522 + "crashed was not found for id %lu.\n",
526 #endif /* !UNIV_HOTBACKUP */
527 --- a/storage/innodb_plugin/dict/dict0mem.c
528 +++ b/storage/innodb_plugin/dict/dict0mem.c
530 /* The number of transactions that are either waiting on the
531 AUTOINC lock or have been granted the lock. */
532 table->n_waiting_or_granted_auto_inc_locks = 0;
534 + table->is_corrupt = FALSE;
535 #endif /* !UNIV_HOTBACKUP */
537 ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
538 --- a/storage/innodb_plugin/fil/fil0fil.c
539 +++ b/storage/innodb_plugin/fil/fil0fil.c
541 file we have written to */
542 ibool is_in_unflushed_spaces; /*!< TRUE if this space is
543 currently in unflushed_spaces */
545 UT_LIST_NODE_T(fil_space_t) space_list;
546 /*!< list of all spaces */
547 ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
548 @@ -1248,6 +1249,8 @@
549 ut_fold_string(name), space);
550 space->is_in_unflushed_spaces = FALSE;
552 + space->is_corrupt = FALSE;
554 UT_LIST_ADD_LAST(space_list, fil_system->space_list, space);
556 mutex_exit(&fil_system->mutex);
557 @@ -5219,6 +5222,34 @@
558 ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
559 ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
561 + if (srv_pass_corrupt_table == 1 && space->is_corrupt) {
562 + /* should ignore i/o for the crashed space */
563 + mutex_enter(&fil_system->mutex);
564 + fil_node_complete_io(node, fil_system, type);
565 + mutex_exit(&fil_system->mutex);
566 + if (mode == OS_AIO_NORMAL) {
567 + ut_a(space->purpose == FIL_TABLESPACE);
568 + buf_page_io_complete(message);
570 + if (type == OS_FILE_READ) {
571 + return(DB_TABLESPACE_DELETED);
573 + return(DB_SUCCESS);
576 + if (srv_pass_corrupt_table > 1 && space->is_corrupt) {
577 + /* should ignore write i/o for the crashed space */
578 + if (type == OS_FILE_WRITE) {
579 + mutex_enter(&fil_system->mutex);
580 + fil_node_complete_io(node, fil_system, type);
581 + mutex_exit(&fil_system->mutex);
582 + if (mode == OS_AIO_NORMAL) {
583 + ut_a(space->purpose == FIL_TABLESPACE);
584 + buf_page_io_complete(message);
586 + return(DB_SUCCESS);
589 #ifdef UNIV_HOTBACKUP
590 /* In ibbackup do normal i/o, not aio */
591 if (type == OS_FILE_READ) {
592 @@ -5233,6 +5264,8 @@
593 ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
594 offset_low, offset_high, len, node, message, trx);
600 if (mode == OS_AIO_SYNC) {
601 @@ -5726,3 +5759,46 @@
606 +/*************************************************************************
607 +functions to access is_corrupt flag of fil_space_t*/
610 +fil_space_is_corrupt(
611 +/*=================*/
614 + fil_space_t* space;
617 + mutex_enter(&fil_system->mutex);
619 + space = fil_space_get_by_id(space_id);
621 + if (space && space->is_corrupt) {
625 + mutex_exit(&fil_system->mutex);
631 +fil_space_set_corrupt(
632 +/*==================*/
635 + fil_space_t* space;
637 + mutex_enter(&fil_system->mutex);
639 + space = fil_space_get_by_id(space_id);
642 + space->is_corrupt = TRUE;
645 + mutex_exit(&fil_system->mutex);
648 --- a/storage/innodb_plugin/fsp/fsp0fsp.c
649 +++ b/storage/innodb_plugin/fsp/fsp0fsp.c
651 ut_ad(id || !zip_size);
653 block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
655 + if (srv_pass_corrupt_table && !block) {
660 header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
661 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
664 fsp_header_t* sp_header;
666 block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
668 + if (srv_pass_corrupt_table && !block) {
673 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
675 sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
676 @@ -1867,6 +1879,11 @@
680 + if (srv_pass_corrupt_table && !page) {
681 + return(ULINT_UNDEFINED);
685 for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
687 inode = fsp_seg_inode_page_get_nth_inode(
688 @@ -1980,6 +1997,11 @@
690 page = buf_block_get_frame(block);
692 + if (srv_pass_corrupt_table && !page) {
697 n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
699 ut_a(n != ULINT_UNDEFINED);
700 @@ -2073,6 +2095,11 @@
702 inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
704 + if (srv_pass_corrupt_table && !inode) {
710 (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) {
712 @@ -2100,7 +2127,7 @@
715 = fseg_inode_try_get(header, space, zip_size, mtr);
717 + ut_a(srv_pass_corrupt_table || inode);
721 @@ -3309,6 +3336,11 @@
723 descr = xdes_get_descriptor(space, zip_size, page, mtr);
725 + if (srv_pass_corrupt_table && !descr) {
726 + /* The page may be corrupt. pass it. */
731 if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
732 fputs("InnoDB: Dump of the tablespace extent descriptor: ",
733 @@ -3561,6 +3593,11 @@
735 descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
737 + if (srv_pass_corrupt_table && !descr) {
738 + /* The page may be corrupt. pass it. */
742 /* Check that the header resides on a page which has not been
745 @@ -3645,6 +3682,12 @@
747 inode = fseg_inode_get(header, space, zip_size, mtr);
749 + if (srv_pass_corrupt_table && !inode) {
750 + /* ignore the corruption */
755 descr = fseg_get_first_extent(inode, space, zip_size, mtr);
758 --- a/storage/innodb_plugin/handler/ha_innodb.cc
759 +++ b/storage/innodb_plugin/handler/ha_innodb.cc
760 @@ -3738,6 +3738,12 @@
764 + if (srv_pass_corrupt_table <= 1 && share->ib_table && share->ib_table->is_corrupt) {
767 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
770 /* Create buffers for packing the fields of a record. Why
771 table->reclength did not work here? Obviously, because char
772 fields when packed actually became 1 byte longer, when we also
773 @@ -3765,6 +3771,19 @@
774 /* Get pointer to a table object in InnoDB dictionary cache */
775 ib_table = dict_table_get(norm_name, TRUE);
777 + if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) {
779 + my_free(upd_buff, MYF(0));
781 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
784 + share->ib_table = ib_table;
790 if (NULL == ib_table) {
791 if (is_part && retries < 10) {
793 @@ -4912,6 +4931,10 @@
795 ha_statistic_increment(&SSV::ha_write_count);
797 + if (share->ib_table->is_corrupt) {
798 + DBUG_RETURN(HA_ERR_CRASHED);
801 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
802 table->timestamp_field->set_time();
804 @@ -5125,6 +5148,10 @@
806 innobase_active_small();
808 + if (share->ib_table->is_corrupt) {
809 + DBUG_RETURN(HA_ERR_CRASHED);
812 DBUG_RETURN(error_result);
815 @@ -5301,6 +5328,10 @@
817 ha_statistic_increment(&SSV::ha_update_count);
819 + if (share->ib_table->is_corrupt) {
820 + DBUG_RETURN(HA_ERR_CRASHED);
823 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
824 table->timestamp_field->set_time();
826 @@ -5386,6 +5417,10 @@
828 innobase_active_small();
830 + if (share->ib_table->is_corrupt) {
831 + DBUG_RETURN(HA_ERR_CRASHED);
837 @@ -5407,6 +5442,10 @@
839 ha_statistic_increment(&SSV::ha_delete_count);
841 + if (share->ib_table->is_corrupt) {
842 + DBUG_RETURN(HA_ERR_CRASHED);
845 if (!prebuilt->upd_node) {
846 row_get_prebuilt_update_vector(prebuilt);
848 @@ -5429,6 +5468,10 @@
850 innobase_active_small();
852 + if (share->ib_table->is_corrupt) {
853 + DBUG_RETURN(HA_ERR_CRASHED);
859 @@ -5668,6 +5711,10 @@
861 ha_statistic_increment(&SSV::ha_read_key_count);
863 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
864 + DBUG_RETURN(HA_ERR_CRASHED);
867 index = prebuilt->index;
869 if (UNIV_UNLIKELY(index == NULL)) {
870 @@ -5733,6 +5780,10 @@
871 ret = DB_UNSUPPORTED;
874 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
875 + DBUG_RETURN(HA_ERR_CRASHED);
881 @@ -5843,6 +5894,10 @@
883 DBUG_ENTER("change_active_index");
885 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
886 + DBUG_RETURN(HA_ERR_CRASHED);
889 ut_ad(user_thd == ha_thd());
890 ut_a(prebuilt->trx == thd_to_trx(user_thd));
892 @@ -5933,6 +5988,10 @@
894 DBUG_ENTER("general_fetch");
896 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
897 + DBUG_RETURN(HA_ERR_CRASHED);
900 ut_a(prebuilt->trx == thd_to_trx(user_thd));
902 innodb_srv_conc_enter_innodb(prebuilt->trx);
903 @@ -5942,6 +6001,10 @@
905 innodb_srv_conc_exit_innodb(prebuilt->trx);
907 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
908 + DBUG_RETURN(HA_ERR_CRASHED);
914 @@ -7189,6 +7252,10 @@
915 DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
918 + if (share->ib_table->is_corrupt) {
919 + DBUG_RETURN(HA_ERR_CRASHED);
922 /* Truncate the table in InnoDB */
924 error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
925 @@ -7197,6 +7264,10 @@
929 + if (share->ib_table->is_corrupt) {
930 + DBUG_RETURN(HA_ERR_CRASHED);
933 error = convert_error_code_to_mysql(error, prebuilt->table->flags,
936 @@ -7701,6 +7772,16 @@
937 return(ranges + (double) rows / (double) total_rows * time_for_scan);
942 +ha_innobase::is_corrupt() const
944 + if (share->ib_table)
945 + return ((bool)share->ib_table->is_corrupt);
950 /*********************************************************************//**
951 Calculates the key number used inside MySQL for an Innobase index. We will
952 first check the "index translation table" for a match of the index to get
953 @@ -7881,7 +7962,7 @@
954 ib_table = prebuilt->table;
956 if (flag & HA_STATUS_TIME) {
957 - if (called_from_analyze || innobase_stats_on_metadata) {
958 + if ((called_from_analyze || innobase_stats_on_metadata) && !share->ib_table->is_corrupt) {
959 /* In sql_show we call with this flag: update
960 then statistics so that they are up-to-date */
962 @@ -8154,10 +8235,18 @@
963 THD* thd, /*!< in: connection thread handle */
964 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
966 + if (share->ib_table->is_corrupt) {
967 + return(HA_ADMIN_CORRUPT);
970 /* Simply call ::info() with all the flags */
971 info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
972 true /* called from analyze */);
974 + if (share->ib_table->is_corrupt) {
975 + return(HA_ADMIN_CORRUPT);
981 @@ -8339,6 +8428,10 @@
982 my_error(ER_QUERY_INTERRUPTED, MYF(0));
985 + if (share->ib_table->is_corrupt) {
986 + return(HA_ADMIN_CORRUPT);
989 DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
992 @@ -9072,6 +9165,10 @@
996 + if (share->ib_table->is_corrupt) {
997 + DBUG_RETURN(HA_ERR_CRASHED);
1000 if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) {
1001 ut_print_timestamp(stderr);
1003 @@ -11497,6 +11594,14 @@
1004 "dump file (if present). Disabled by default.",
1007 +static MYSQL_SYSVAR_ULONG(pass_corrupt_table, srv_pass_corrupt_table,
1008 + PLUGIN_VAR_RQCMDARG,
1009 + "Pass corruptions of user tables as 'corrupt table' instead of not crashing itself, "
1010 + "when used with file_per_table. "
1011 + "All file io for the datafile after detected as corrupt are disabled, "
1012 + "except for the deletion.",
1013 + NULL, NULL, 0, 0, 2, 0);
1015 static struct st_mysql_sys_var* innobase_system_variables[]= {
1016 MYSQL_SYSVAR(additional_mem_pool_size),
1017 MYSQL_SYSVAR(autoextend_increment),
1018 @@ -11581,6 +11686,7 @@
1019 MYSQL_SYSVAR(auto_lru_dump),
1020 MYSQL_SYSVAR(blocking_lru_restore),
1021 MYSQL_SYSVAR(use_purge_thread),
1022 + MYSQL_SYSVAR(pass_corrupt_table),
1026 --- a/storage/innodb_plugin/handler/ha_innodb.h
1027 +++ b/storage/innodb_plugin/handler/ha_innodb.h
1029 innodb_idx_translate_t idx_trans_tbl; /*!< index translation
1030 table between MySQL and
1032 + dict_table_t* ib_table;
1039 double read_time(uint index, uint ranges, ha_rows rows);
1040 + bool is_corrupt() const;
1042 int write_row(uchar * buf);
1043 int update_row(const uchar * old_data, uchar * new_data);
1044 --- a/storage/innodb_plugin/handler/innodb_patch_info.h
1045 +++ b/storage/innodb_plugin/handler/innodb_patch_info.h
1047 {"innodb_extend_slow","Extended statistics in slow.log","It is InnoDB-part only. It needs to patch also to mysqld.","http://www.percona.com/docs/wiki/percona-xtradb"},
1048 {"innodb_lru_dump_restore","Dump and restore command for content of buffer pool","","http://www.percona.com/docs/wiki/percona-xtradb"},
1049 {"innodb_separate_doublewrite","Add option 'innodb_doublewrite_file' to separate doublewrite dedicated tablespace","","http://www.percona.com/docs/wiki/percona-xtradb"},
1050 +{"innodb_pass_corrupt_table","Treat tables as corrupt instead of crash, when meet corrupt blocks","","http://www.percona.com/docs/wiki/percona-xtradb"},
1051 {NULL, NULL, NULL, NULL}
1053 --- a/storage/innodb_plugin/include/btr0btr.ic
1054 +++ b/storage/innodb_plugin/include/btr0btr.ic
1056 #include "mtr0mtr.h"
1057 #include "mtr0log.h"
1058 #include "page0zip.h"
1060 +#include "srv0srv.h"
1061 #define BTR_MAX_NODE_LEVEL 50 /*!< Maximum B-tree page level
1062 (not really a hard limit).
1063 Used in debug assertions
1065 block = buf_page_get_gen(space, zip_size, page_no, mode,
1066 NULL, BUF_GET, file, line, mtr);
1068 - if (mode != RW_NO_LATCH) {
1069 + ut_a(srv_pass_corrupt_table || block);
1071 + if (block && mode != RW_NO_LATCH) {
1073 buf_block_dbg_add_level(block, SYNC_TREE_NODE);
1075 --- a/storage/innodb_plugin/include/buf0buf.h
1076 +++ b/storage/innodb_plugin/include/buf0buf.h
1078 const buf_block_t* block) /*!< in: pointer to the control block */
1079 __attribute__((pure));
1080 #else /* UNIV_DEBUG */
1081 -# define buf_block_get_frame(block) (block)->frame
1082 +# define buf_block_get_frame(block) (block ? (block)->frame : 0)
1083 #endif /* UNIV_DEBUG */
1084 /*********************************************************************//**
1085 Gets the space id of a block.
1086 @@ -1198,6 +1198,7 @@
1087 0 if the block was never accessed
1088 in the buffer pool */
1091 # if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1092 ibool file_page_was_freed;
1093 /*!< this is set to TRUE when fsp
1094 --- a/storage/innodb_plugin/include/buf0buf.ic
1095 +++ b/storage/innodb_plugin/include/buf0buf.ic
1097 #include "buf0flu.h"
1098 #include "buf0lru.h"
1099 #include "buf0rea.h"
1101 +#include "srv0srv.h"
1102 /********************************************************************//**
1103 Reads the freed_page_clock of a buffer block.
1104 @return freed_page_clock */
1105 @@ -597,6 +597,12 @@
1106 /*================*/
1107 const buf_block_t* block) /*!< in: pointer to the control block */
1109 + ut_a(srv_pass_corrupt_table || block);
1111 + if (srv_pass_corrupt_table && !block) {
1117 switch (buf_block_get_state(block)) {
1118 --- a/storage/innodb_plugin/include/dict0dict.h
1119 +++ b/storage/innodb_plugin/include/dict0dict.h
1120 @@ -1197,6 +1197,15 @@
1124 +/*************************************************************************
1125 +set is_corrupt flag by space_id*/
1128 +dict_table_set_corrupt_by_space(
1129 +/*============================*/
1131 + ibool need_mutex);
1134 #include "dict0dict.ic"
1136 --- a/storage/innodb_plugin/include/dict0mem.h
1137 +++ b/storage/innodb_plugin/include/dict0mem.h
1139 the AUTOINC lock on this table. */
1141 /*----------------------*/
1143 #endif /* !UNIV_HOTBACKUP */
1146 --- a/storage/innodb_plugin/include/fil0fil.h
1147 +++ b/storage/innodb_plugin/include/fil0fil.h
1148 @@ -749,6 +749,19 @@
1149 fil_system_hash_nodes(void);
1150 /*========================*/
1152 +/*************************************************************************
1153 +functions to access is_corrupt flag of fil_space_t*/
1156 +fil_space_is_corrupt(
1157 +/*=================*/
1161 +fil_space_set_corrupt(
1162 +/*==================*/
1165 typedef struct fil_space_struct fil_space_t;
1168 --- a/storage/innodb_plugin/include/fut0fut.ic
1169 +++ b/storage/innodb_plugin/include/fut0fut.ic
1171 Created 12/13/1995 Heikki Tuuri
1172 ***********************************************************************/
1174 +#include "srv0srv.h"
1175 #include "sync0rw.h"
1176 #include "buf0buf.h"
1179 ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
1181 block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr);
1183 + if (srv_pass_corrupt_table && !block) {
1188 ptr = buf_block_get_frame(block) + addr.boffset;
1190 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
1191 --- a/storage/innodb_plugin/include/page0page.h
1192 +++ b/storage/innodb_plugin/include/page0page.h
1196 const page_t* page) /*!< in: page */
1197 - __attribute__((nonnull, pure));
1198 + __attribute__((pure));
1199 /************************************************************//**
1200 Gets the pointer to the next record on the page.
1201 @return pointer to next record */
1202 --- a/storage/innodb_plugin/include/page0page.ic
1203 +++ b/storage/innodb_plugin/include/page0page.ic
1206 const page_t* page) /*!< in: page */
1211 return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
1214 --- a/storage/innodb_plugin/include/page0zip.h
1215 +++ b/storage/innodb_plugin/include/page0zip.h
1217 const page_t* page, /*!< in: uncompressed page */
1218 dict_index_t* index, /*!< in: index of the B-tree node */
1219 mtr_t* mtr) /*!< in: mini-transaction, or NULL */
1220 - __attribute__((nonnull(1,2,3)));
1221 + __attribute__((nonnull(1,3)));
1223 /**********************************************************************//**
1224 Decompress a page. This function should tolerate errors on the compressed
1225 --- a/storage/innodb_plugin/include/srv0srv.h
1226 +++ b/storage/innodb_plugin/include/srv0srv.h
1228 extern ulint srv_adaptive_checkpoint;
1230 extern ulint srv_expand_import;
1231 +extern ulint srv_pass_corrupt_table;
1233 extern ulint srv_extra_rsegments;
1234 extern ulint srv_dict_size_limit;
1235 --- a/storage/innodb_plugin/page/page0zip.c
1236 +++ b/storage/innodb_plugin/page/page0zip.c
1237 @@ -1195,6 +1195,10 @@
1238 FILE* logfile = NULL;
1245 ut_a(page_is_comp(page));
1246 ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
1247 ut_ad(page_simple_validate_new((page_t*) page));
1248 --- a/storage/innodb_plugin/row/row0ins.c
1249 +++ b/storage/innodb_plugin/row/row0ins.c
1250 @@ -1348,6 +1348,12 @@
1251 const rec_t* rec = btr_pcur_get_rec(&pcur);
1252 const buf_block_t* block = btr_pcur_get_block(&pcur);
1254 + if (srv_pass_corrupt_table && !block) {
1255 + err = DB_CORRUPTION;
1260 if (page_rec_is_infimum(rec)) {
1263 --- a/storage/innodb_plugin/row/row0merge.c
1264 +++ b/storage/innodb_plugin/row/row0merge.c
1265 @@ -1224,6 +1224,13 @@
1267 if (UNIV_LIKELY(has_next)) {
1268 rec = btr_pcur_get_rec(&pcur);
1270 + if (srv_pass_corrupt_table && !rec) {
1271 + err = DB_CORRUPTION;
1276 offsets = rec_get_offsets(rec, clust_index, NULL,
1277 ULINT_UNDEFINED, &row_heap);
1279 --- a/storage/innodb_plugin/row/row0sel.c
1280 +++ b/storage/innodb_plugin/row/row0sel.c
1281 @@ -3896,6 +3896,13 @@
1282 /* PHASE 4: Look for matching records in a loop */
1284 rec = btr_pcur_get_rec(pcur);
1286 + if (srv_pass_corrupt_table && !rec) {
1287 + err = DB_CORRUPTION;
1288 + goto lock_wait_or_error;
1292 ut_ad(!!page_rec_is_comp(rec) == comp);
1293 #ifdef UNIV_SEARCH_DEBUG
1295 @@ -3973,7 +3980,13 @@
1296 if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
1299 - if (srv_force_recovery == 0 || moves_up == FALSE) {
1300 + if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
1301 + index->table->is_corrupt = TRUE;
1302 + fil_space_set_corrupt(index->table->space);
1305 + if ((srv_force_recovery == 0 || moves_up == FALSE)
1306 + && srv_pass_corrupt_table <= 1) {
1307 ut_print_timestamp(stderr);
1308 buf_page_print(page_align(rec), 0);
1310 @@ -4024,7 +4037,8 @@
1312 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
1314 - if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
1315 + if (UNIV_UNLIKELY(srv_force_recovery > 0)
1316 + || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) {
1317 if (!rec_validate(rec, offsets)
1318 || !btr_index_rec_validate(rec, index, FALSE)) {
1320 --- a/storage/innodb_plugin/srv/srv0srv.c
1321 +++ b/storage/innodb_plugin/srv/srv0srv.c
1323 UNIV_INTERN ulint srv_adaptive_checkpoint = 0; /* 0: none 1: reflex 2: estimate */
1325 UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */
1326 +UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
1328 UNIV_INTERN ulint srv_extra_rsegments = 0; /* extra rseg for users */
1329 UNIV_INTERN ulint srv_dict_size_limit = 0;
1330 --- a/storage/innodb_plugin/srv/srv0start.c
1331 +++ b/storage/innodb_plugin/srv/srv0start.c
1332 @@ -2006,6 +2006,13 @@
1334 os_fast_mutex_free(&srv_os_test_mutex);
1336 + if (!srv_file_per_table_original_value
1337 + && srv_pass_corrupt_table) {
1338 + fprintf(stderr, "InnoDB: Warning:"
1339 + " innodb_file_per_table is diabled."
1340 + " So innodb_pass_corrupt_table doesn't make sence\n");
1343 if (srv_print_verbose_log) {
1344 ut_print_timestamp(stderr);