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/innobase/btr/btr0btr.c
9 +++ b/storage/innobase/btr/btr0btr.c
12 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
15 + if (srv_pass_corrupt_table && !block) {
20 btr_assert_not_corrupted(block, index);
22 if (!dict_index_is_ibuf(index)) {
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 @@ -1457,6 +1469,13 @@
38 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
41 + if (srv_pass_corrupt_table && !root) {
48 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
50 @@ -1480,6 +1499,12 @@
52 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
55 + if (srv_pass_corrupt_table && !root) {
61 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
63 @@ -1513,6 +1538,11 @@
64 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
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/innobase/btr/btr0cur.c
76 +++ b/storage/innobase/btr/btr0cur.c
78 mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH;
79 get_block = btr_block_get(
80 space, zip_size, page_no, mode, cursor->index, 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(
91 space, zip_size, left_page_no,
92 RW_X_LATCH, cursor->index, mtr);
94 + if (srv_pass_corrupt_table && !get_block) {
99 ut_a(page_is_comp(get_block->frame)
100 == page_is_comp(page));
102 get_block = btr_block_get(
103 space, zip_size, page_no,
104 RW_X_LATCH, cursor->index, mtr);
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(
115 space, zip_size, right_page_no,
116 RW_X_LATCH, cursor->index, mtr);
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));
127 left_page_no, mode, cursor->index, 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));
139 get_block = btr_block_get(
140 space, zip_size, page_no, mode, cursor->index, 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 */
153 + if (srv_pass_corrupt_table
154 + && buf_mode != BUF_GET_IF_IN_POOL
155 + && buf_mode != BUF_GET_IF_IN_POOL_OR_WATCH) {
156 + page_cursor->block = 0;
157 + page_cursor->rec = 0;
159 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
163 + ut_a(buf_mode == BUF_GET_IF_IN_POOL
164 + || buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH);
166 /* This must be a search to perform an insert/delete
167 mark/ delete; try using the insert/delete buffer */
170 block->check_index_page_at_flush = TRUE;
171 page = buf_block_get_frame(block);
173 + if (srv_pass_corrupt_table && !page) {
174 + page_cursor->block = 0;
175 + page_cursor->rec = 0;
177 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
183 if (rw_latch != RW_NO_LATCH) {
184 #ifdef UNIV_ZIP_DEBUG
185 const page_zip_des_t* page_zip
187 RW_NO_LATCH, NULL, BUF_GET,
189 page = buf_block_get_frame(block);
191 + if (srv_pass_corrupt_table && !page) {
192 + page_cursor->block = 0;
193 + page_cursor->rec = 0;
195 + cursor->path_arr->nth_rec = ULINT_UNDEFINED;
201 ut_ad(index->id == btr_page_get_index_id(page));
203 block->check_index_page_at_flush = TRUE;
204 @@ -982,6 +1046,14 @@
205 RW_NO_LATCH, NULL, BUF_GET,
207 page = buf_block_get_frame(block);
209 + if (srv_pass_corrupt_table && !page) {
210 + page_cursor->block = 0;
211 + page_cursor->rec = 0;
216 ut_ad(index->id == btr_page_get_index_id(page));
218 if (height == ULINT_UNDEFINED) {
219 @@ -1195,6 +1267,12 @@
222 block = btr_cur_get_block(cursor);
224 + if (srv_pass_corrupt_table && !block) {
225 + return(DB_CORRUPTION);
229 page = buf_block_get_frame(block);
230 index = cursor->index;
231 zip_size = buf_block_get_zip_size(block);
232 @@ -2927,6 +3005,11 @@
234 block = btr_cur_get_block(cursor);
236 + if (srv_pass_corrupt_table && !block) {
237 + return(DB_CORRUPTION);
241 ut_ad(page_is_leaf(buf_block_get_frame(block)));
243 rec = btr_cur_get_rec(cursor);
244 @@ -3635,6 +3718,11 @@
246 page = btr_cur_get_page(&cursor);
248 + if (srv_pass_corrupt_table && !page) {
253 rec = page_rec_get_next(page_get_infimum_rec(page));
255 if (!page_rec_is_supremum(rec)) {
256 --- a/storage/innobase/btr/btr0pcur.c
257 +++ b/storage/innobase/btr/btr0pcur.c
263 +#include "srv0srv.h"
264 /**************************************************************//**
265 Allocates memory for a persistent cursor object and initializes the cursor.
266 @return own: persistent cursor */
268 ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
270 block = btr_pcur_get_block(cursor);
272 + if (srv_pass_corrupt_table && !block) {
277 index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
279 page_cursor = btr_pcur_get_page_cur(cursor);
282 btr_pcur_get_btr_cur(cursor)->index, mtr);
283 next_page = buf_block_get_frame(next_block);
285 + if (srv_pass_corrupt_table && !next_page) {
286 + btr_leaf_page_release(btr_pcur_get_block(cursor),
287 + cursor->latch_mode, mtr);
288 + btr_pcur_get_page_cur(cursor)->block = 0;
289 + btr_pcur_get_page_cur(cursor)->rec = 0;
293 #ifdef UNIV_BTR_DEBUG
294 ut_a(page_is_comp(next_page) == page_is_comp(page));
295 ut_a(btr_page_get_prev(next_page, mtr)
296 --- a/storage/innobase/btr/btr0sea.c
297 +++ b/storage/innobase/btr/btr0sea.c
299 #include "btr0pcur.h"
303 +#include "srv0srv.h"
304 /** Flag: has the search system been enabled?
305 Protected by btr_search_latch. */
306 UNIV_INTERN char btr_search_enabled = TRUE;
309 block = btr_cur_get_block(cursor);
311 + if (srv_pass_corrupt_table && !block) {
316 /* NOTE that the following two function calls do NOT protect
317 info or block->n_fields etc. with any semaphore, to save CPU time!
318 We cannot assume the fields are consistent when we return from
319 --- a/storage/innobase/buf/buf0buf.c
320 +++ b/storage/innobase/buf/buf0buf.c
322 #include "log0recv.h"
323 #include "page0zip.h"
325 +#include "srv0start.h"
327 /* prototypes for new functions added to ha_innodb.cc */
328 trx_t* innobase_get_trx();
329 @@ -1150,6 +1151,11 @@
330 ready = buf_flush_ready_for_replace(&block->page);
331 mutex_exit(&block->mutex);
333 + if (block->page.is_corrupt) {
334 + /* corrupt page may remain, it can be skipped */
341 @@ -1946,6 +1952,13 @@
345 + if (srv_pass_corrupt_table <= 1) {
346 + if (bpage->is_corrupt) {
347 + rw_lock_s_unlock(&buf_pool->page_hash_latch);
352 block_mutex = buf_page_get_mutex_enter(bpage);
354 rw_lock_s_unlock(&buf_pool->page_hash_latch);
355 @@ -2525,6 +2538,13 @@
359 + if (srv_pass_corrupt_table <= 1) {
360 + if (block->page.is_corrupt) {
361 + mutex_exit(block_mutex);
366 switch (buf_block_get_state(block)) {
369 @@ -3199,6 +3219,7 @@
370 bpage->newest_modification = 0;
371 bpage->oldest_modification = 0;
372 HASH_INVALIDATE(bpage, hash);
373 + bpage->is_corrupt = FALSE;
374 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
375 bpage->file_page_was_freed = FALSE;
376 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
377 @@ -3837,6 +3858,7 @@
378 (ulong) bpage->offset);
381 + if (!srv_pass_corrupt_table || !bpage->is_corrupt) {
382 /* From version 3.23.38 up we store the page checksum
383 to the 4 first bytes of the page end lsn field */
385 @@ -3878,6 +3900,23 @@
386 REFMAN "forcing-innodb-recovery.html\n"
387 "InnoDB: about forcing recovery.\n", stderr);
389 + if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space)
390 + && bpage->space < SRV_LOG_SPACE_FIRST_ID) {
394 + "InnoDB: space %u will be treated as corrupt.\n",
396 + fil_space_set_corrupt(bpage->space);
398 + trx = innobase_get_trx();
399 + if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) {
400 + dict_table_set_corrupt_by_space(bpage->space, FALSE);
402 + dict_table_set_corrupt_by_space(bpage->space, TRUE);
404 + bpage->is_corrupt = TRUE;
406 if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
407 /* If page space id is larger than TRX_SYS_SPACE
408 (0), we will attempt to mark the corresponding
409 @@ -3894,6 +3933,7 @@
415 if (recv_recovery_is_on()) {
416 /* Pages must be uncompressed for crash recovery. */
417 @@ -3903,8 +3943,11 @@
419 if (uncompressed && !recv_no_ibuf_operations) {
420 ibuf_merge_or_delete_for_page(
421 + /* Delete possible entries, if bpage is_corrupt */
422 + (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
423 (buf_block_t*) bpage, bpage->space,
424 bpage->offset, buf_page_get_zip_size(bpage),
425 + (srv_pass_corrupt_table && bpage->is_corrupt) ? FALSE :
429 --- a/storage/innobase/buf/buf0rea.c
430 +++ b/storage/innobase/buf/buf0rea.c
432 ((buf_block_t*) bpage)->frame, bpage, trx);
436 + if (srv_pass_corrupt_table) {
437 + if (*err != DB_SUCCESS) {
438 + bpage->is_corrupt = TRUE;
441 ut_a(*err == DB_SUCCESS);
445 /* The i/o is already completed when we arrive from
446 --- a/storage/innobase/dict/dict0dict.c
447 +++ b/storage/innobase/dict/dict0dict.c
449 #include "m_ctype.h" /* my_isspace() */
450 #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
452 +#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
458 mutex_exit(&(dict_sys->mutex));
460 - if (table != NULL) {
461 + if (table != NULL && !table->is_corrupt) {
462 /* If table->ibd_file_missing == TRUE, this will
463 print an error message and return without doing
465 @@ -1298,7 +1299,7 @@
466 + dict_sys->size) > srv_dict_size_limit ) {
467 prev_table = UT_LIST_GET_PREV(table_LRU, table);
469 - if (table == self || table->n_mysql_handles_opened)
470 + if (table == self || table->n_mysql_handles_opened || table->is_corrupt)
473 cached_foreign_tables = 0;
474 @@ -4377,6 +4378,12 @@
475 heap = mem_heap_create(1000);
478 + if (table->is_corrupt) {
479 + ut_a(srv_pass_corrupt_table);
480 + mem_heap_free(heap);
484 size = btr_get_size(index, BTR_TOTAL_SIZE);
486 index->stat_index_size = size;
487 @@ -4524,6 +4531,12 @@
488 heap = mem_heap_create(1000);
491 + if (table->is_corrupt) {
492 + ut_a(srv_pass_corrupt_table);
493 + mem_heap_free(heap);
497 /*===========================================*/
499 dict_table_t* sys_stats;
500 @@ -4716,6 +4729,13 @@
501 || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
502 && dict_index_is_clust(index)))) {
505 + if (table->is_corrupt) {
506 + ut_a(srv_pass_corrupt_table);
507 + dict_table_stats_unlock(table, RW_X_LATCH);
511 size = btr_get_size(index, BTR_TOTAL_SIZE);
513 index->stat_index_size = size;
514 @@ -5695,4 +5715,42 @@
516 index->type |= DICT_CORRUPT;
519 +/*************************************************************************
520 +set is_corrupt flag by space_id*/
523 +dict_table_set_corrupt_by_space(
524 +/*============================*/
528 + dict_table_t* table;
529 + ibool found = FALSE;
531 + ut_a(!trx_sys_sys_space(space_id) && space_id < SRV_LOG_SPACE_FIRST_ID);
534 + mutex_enter(&(dict_sys->mutex));
536 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
539 + if (table->space == space_id) {
540 + table->is_corrupt = TRUE;
544 + table = UT_LIST_GET_NEXT(table_LRU, table);
548 + mutex_exit(&(dict_sys->mutex));
551 + fprintf(stderr, "InnoDB: space to be marked as "
552 + "crashed was not found for id %lu.\n",
556 #endif /* !UNIV_HOTBACKUP */
557 --- a/storage/innobase/dict/dict0mem.c
558 +++ b/storage/innobase/dict/dict0mem.c
560 /* The number of transactions that are either waiting on the
561 AUTOINC lock or have been granted the lock. */
562 table->n_waiting_or_granted_auto_inc_locks = 0;
564 + table->is_corrupt = FALSE;
565 #endif /* !UNIV_HOTBACKUP */
567 ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
568 --- a/storage/innobase/fil/fil0fil.c
569 +++ b/storage/innobase/fil/fil0fil.c
571 file we have written to */
572 ibool is_in_unflushed_spaces; /*!< TRUE if this space is
573 currently in unflushed_spaces */
575 UT_LIST_NODE_T(fil_space_t) space_list;
576 /*!< list of all spaces */
577 ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
578 @@ -1294,6 +1295,8 @@
579 ut_fold_string(name), space);
580 space->is_in_unflushed_spaces = FALSE;
582 + space->is_corrupt = FALSE;
584 UT_LIST_ADD_LAST(space_list, fil_system->space_list, space);
586 mutex_exit(&fil_system->mutex);
587 @@ -5285,6 +5288,34 @@
588 ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
589 ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
591 + if (srv_pass_corrupt_table == 1 && space->is_corrupt) {
592 + /* should ignore i/o for the crashed space */
593 + mutex_enter(&fil_system->mutex);
594 + fil_node_complete_io(node, fil_system, type);
595 + mutex_exit(&fil_system->mutex);
596 + if (mode == OS_AIO_NORMAL) {
597 + ut_a(space->purpose == FIL_TABLESPACE);
598 + buf_page_io_complete(message);
600 + if (type == OS_FILE_READ) {
601 + return(DB_TABLESPACE_DELETED);
603 + return(DB_SUCCESS);
606 + if (srv_pass_corrupt_table > 1 && space->is_corrupt) {
607 + /* should ignore write i/o for the crashed space */
608 + if (type == OS_FILE_WRITE) {
609 + mutex_enter(&fil_system->mutex);
610 + fil_node_complete_io(node, fil_system, type);
611 + mutex_exit(&fil_system->mutex);
612 + if (mode == OS_AIO_NORMAL) {
613 + ut_a(space->purpose == FIL_TABLESPACE);
614 + buf_page_io_complete(message);
616 + return(DB_SUCCESS);
619 #ifdef UNIV_HOTBACKUP
620 /* In ibbackup do normal i/o, not aio */
621 if (type == OS_FILE_READ) {
622 @@ -5299,6 +5330,8 @@
623 ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
624 offset_low, offset_high, len, node, message, trx);
630 if (mode == OS_AIO_SYNC) {
631 @@ -5799,3 +5832,46 @@
636 +/*************************************************************************
637 +functions to access is_corrupt flag of fil_space_t*/
640 +fil_space_is_corrupt(
641 +/*=================*/
644 + fil_space_t* space;
647 + mutex_enter(&fil_system->mutex);
649 + space = fil_space_get_by_id(space_id);
651 + if (space && space->is_corrupt) {
655 + mutex_exit(&fil_system->mutex);
661 +fil_space_set_corrupt(
662 +/*==================*/
665 + fil_space_t* space;
667 + mutex_enter(&fil_system->mutex);
669 + space = fil_space_get_by_id(space_id);
672 + space->is_corrupt = TRUE;
675 + mutex_exit(&fil_system->mutex);
678 --- a/storage/innobase/fsp/fsp0fsp.c
679 +++ b/storage/innobase/fsp/fsp0fsp.c
681 ut_ad(id || !zip_size);
683 block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
685 + if (srv_pass_corrupt_table && !block) {
690 header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
691 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
694 fsp_header_t* sp_header;
696 block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
698 + if (srv_pass_corrupt_table && !block) {
703 buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
705 sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
706 @@ -1805,6 +1817,11 @@
710 + if (srv_pass_corrupt_table && !page) {
711 + return(ULINT_UNDEFINED);
715 for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
717 inode = fsp_seg_inode_page_get_nth_inode(
718 @@ -1918,6 +1935,11 @@
720 page = buf_block_get_frame(block);
722 + if (srv_pass_corrupt_table && !page) {
727 n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
729 ut_a(n != ULINT_UNDEFINED);
730 @@ -2011,6 +2033,11 @@
732 inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
734 + if (srv_pass_corrupt_table && !inode) {
739 if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
742 @@ -2037,7 +2064,7 @@
745 = fseg_inode_try_get(header, space, zip_size, mtr);
747 + ut_a(srv_pass_corrupt_table || inode);
751 @@ -3243,6 +3270,11 @@
753 descr = xdes_get_descriptor(space, zip_size, page, mtr);
755 + if (srv_pass_corrupt_table && !descr) {
756 + /* The page may be corrupt. pass it. */
761 if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
762 fputs("InnoDB: Dump of the tablespace extent descriptor: ",
763 @@ -3490,6 +3522,11 @@
765 descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
767 + if (srv_pass_corrupt_table && !descr) {
768 + /* The page may be corrupt. pass it. */
772 /* Check that the header resides on a page which has not been
775 @@ -3574,6 +3611,12 @@
777 inode = fseg_inode_get(header, space, zip_size, mtr);
779 + if (srv_pass_corrupt_table && !inode) {
780 + /* ignore the corruption */
785 descr = fseg_get_first_extent(inode, space, zip_size, mtr);
788 --- a/storage/innobase/handler/ha_innodb.cc
789 +++ b/storage/innobase/handler/ha_innodb.cc
790 @@ -4024,6 +4024,12 @@
794 + if (srv_pass_corrupt_table <= 1 && share->ib_table && share->ib_table->is_corrupt) {
797 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
800 /* Will be allocated if it is needed in ::update_row() */
803 @@ -4043,6 +4049,17 @@
804 /* Get pointer to a table object in InnoDB dictionary cache */
805 ib_table = dict_table_get(norm_name, TRUE);
807 + if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) {
813 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
816 + share->ib_table = ib_table;
818 if (NULL == ib_table) {
819 if (is_part && retries < 10) {
820 /* MySQL partition engine hard codes the file name
821 @@ -5263,6 +5280,10 @@
823 ha_statistic_increment(&SSV::ha_write_count);
825 + if (share->ib_table->is_corrupt) {
826 + DBUG_RETURN(HA_ERR_CRASHED);
829 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
830 table->timestamp_field->set_time();
832 @@ -5479,6 +5500,10 @@
834 innobase_active_small();
836 + if (share->ib_table->is_corrupt) {
837 + DBUG_RETURN(HA_ERR_CRASHED);
840 DBUG_RETURN(error_result);
843 @@ -5673,6 +5698,10 @@
845 ha_statistic_increment(&SSV::ha_update_count);
847 + if (share->ib_table->is_corrupt) {
848 + DBUG_RETURN(HA_ERR_CRASHED);
851 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
852 table->timestamp_field->set_time();
854 @@ -5760,6 +5789,10 @@
856 innobase_active_small();
858 + if (share->ib_table->is_corrupt) {
859 + DBUG_RETURN(HA_ERR_CRASHED);
865 @@ -5781,6 +5814,10 @@
867 ha_statistic_increment(&SSV::ha_delete_count);
869 + if (share->ib_table->is_corrupt) {
870 + DBUG_RETURN(HA_ERR_CRASHED);
873 if (!prebuilt->upd_node) {
874 row_get_prebuilt_update_vector(prebuilt);
876 @@ -5807,6 +5844,10 @@
878 innobase_active_small();
880 + if (share->ib_table->is_corrupt) {
881 + DBUG_RETURN(HA_ERR_CRASHED);
887 @@ -6046,6 +6087,10 @@
889 ha_statistic_increment(&SSV::ha_read_key_count);
891 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
892 + DBUG_RETURN(HA_ERR_CRASHED);
895 index = prebuilt->index;
897 if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) {
898 @@ -6113,6 +6158,10 @@
899 ret = DB_UNSUPPORTED;
902 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
903 + DBUG_RETURN(HA_ERR_CRASHED);
909 @@ -6227,6 +6276,10 @@
911 DBUG_ENTER("change_active_index");
913 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
914 + DBUG_RETURN(HA_ERR_CRASHED);
917 ut_ad(user_thd == ha_thd());
918 ut_a(prebuilt->trx == thd_to_trx(user_thd));
920 @@ -6340,6 +6393,10 @@
922 DBUG_ENTER("general_fetch");
924 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
925 + DBUG_RETURN(HA_ERR_CRASHED);
928 ut_a(prebuilt->trx == thd_to_trx(user_thd));
930 innodb_srv_conc_enter_innodb(prebuilt->trx);
931 @@ -6349,6 +6406,10 @@
933 innodb_srv_conc_exit_innodb(prebuilt->trx);
935 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
936 + DBUG_RETURN(HA_ERR_CRASHED);
942 @@ -7615,10 +7676,18 @@
944 update_thd(ha_thd());
946 + if (share->ib_table->is_corrupt) {
947 + DBUG_RETURN(HA_ERR_CRASHED);
950 /* Truncate the table in InnoDB */
952 error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
954 + if (share->ib_table->is_corrupt) {
955 + DBUG_RETURN(HA_ERR_CRASHED);
958 error = convert_error_code_to_mysql(error, prebuilt->table->flags,
961 @@ -8124,6 +8193,16 @@
962 return(ranges + (double) rows / (double) total_rows * time_for_scan);
967 +ha_innobase::is_corrupt() const
969 + if (share->ib_table)
970 + return ((bool)share->ib_table->is_corrupt);
975 /*********************************************************************//**
976 Calculates the key number used inside MySQL for an Innobase index. We will
977 first check the "index translation table" for a match of the index to get
978 @@ -8301,7 +8380,7 @@
979 ib_table = prebuilt->table;
981 if (flag & HA_STATUS_TIME) {
982 - if (called_from_analyze || innobase_stats_on_metadata) {
983 + if ((called_from_analyze || innobase_stats_on_metadata) && !share->ib_table->is_corrupt) {
984 /* In sql_show we call with this flag: update
985 then statistics so that they are up-to-date */
987 @@ -8601,10 +8680,18 @@
988 THD* thd, /*!< in: connection thread handle */
989 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
991 + if (share->ib_table->is_corrupt) {
992 + return(HA_ADMIN_CORRUPT);
995 /* Simply call ::info() with all the flags */
996 info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
997 true /* called from analyze */);
999 + if (share->ib_table->is_corrupt) {
1000 + return(HA_ADMIN_CORRUPT);
1006 @@ -8840,6 +8927,10 @@
1007 my_error(ER_QUERY_INTERRUPTED, MYF(0));
1010 + if (share->ib_table->is_corrupt) {
1011 + return(HA_ADMIN_CORRUPT);
1014 DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
1017 @@ -9610,6 +9701,10 @@
1021 + if (share->ib_table->is_corrupt) {
1022 + DBUG_RETURN(HA_ERR_CRASHED);
1025 if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) {
1026 ut_print_timestamp(stderr);
1028 @@ -12073,6 +12168,26 @@
1029 "dump file (if present). Disabled by default.",
1032 +const char *corrupt_table_action_names[]=
1036 + "salvage", /* 2 */
1039 +TYPELIB corrupt_table_action_typelib=
1041 + array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib",
1042 + corrupt_table_action_names, NULL
1044 +static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
1045 + PLUGIN_VAR_RQCMDARG,
1046 + "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, "
1047 + "when used with file_per_table. "
1048 + "All file io for the datafile after detected as corrupt are disabled, "
1049 + "except for the deletion.",
1050 + NULL, NULL, 0, &corrupt_table_action_typelib);
1052 static struct st_mysql_sys_var* innobase_system_variables[]= {
1053 MYSQL_SYSVAR(additional_mem_pool_size),
1054 MYSQL_SYSVAR(autoextend_increment),
1055 @@ -12166,6 +12281,7 @@
1057 MYSQL_SYSVAR(trx_rseg_n_slots_debug),
1058 #endif /* UNIV_DEBUG */
1059 + MYSQL_SYSVAR(corrupt_table_action),
1063 --- a/storage/innobase/handler/ha_innodb.h
1064 +++ b/storage/innobase/handler/ha_innodb.h
1066 innodb_idx_translate_t idx_trans_tbl; /*!< index translation
1067 table between MySQL and
1069 + dict_table_t* ib_table;
1076 double read_time(uint index, uint ranges, ha_rows rows);
1077 + bool is_corrupt() const;
1079 int write_row(uchar * buf);
1080 int update_row(const uchar * old_data, uchar * new_data);
1081 --- a/storage/innobase/include/btr0btr.ic
1082 +++ b/storage/innobase/include/btr0btr.ic
1084 #include "mtr0mtr.h"
1085 #include "mtr0log.h"
1086 #include "page0zip.h"
1088 +#include "srv0srv.h"
1089 #define BTR_MAX_NODE_LEVEL 50 /*!< Maximum B-tree page level
1090 (not really a hard limit).
1091 Used in debug assertions
1093 block = buf_page_get_gen(space, zip_size, page_no, mode,
1094 NULL, BUF_GET, file, line, mtr);
1096 - if (mode != RW_NO_LATCH) {
1097 + ut_a(srv_pass_corrupt_table || block);
1099 + if (block && mode != RW_NO_LATCH) {
1101 buf_block_dbg_add_level(
1102 block, index != NULL && dict_index_is_ibuf(index)
1103 --- a/storage/innobase/include/buf0buf.h
1104 +++ b/storage/innobase/include/buf0buf.h
1105 @@ -1023,7 +1023,7 @@
1106 const buf_block_t* block) /*!< in: pointer to the control block */
1107 __attribute__((pure));
1108 #else /* UNIV_DEBUG */
1109 -# define buf_block_get_frame(block) (block)->frame
1110 +# define buf_block_get_frame(block) (block ? (block)->frame : 0)
1111 #endif /* UNIV_DEBUG */
1112 /*********************************************************************//**
1113 Gets the space id of a block.
1114 @@ -1470,6 +1470,7 @@
1115 0 if the block was never accessed
1116 in the buffer pool */
1119 # if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1120 ibool file_page_was_freed;
1121 /*!< this is set to TRUE when fsp
1122 --- a/storage/innobase/include/buf0buf.ic
1123 +++ b/storage/innobase/include/buf0buf.ic
1125 #include "buf0flu.h"
1126 #include "buf0lru.h"
1127 #include "buf0rea.h"
1129 +#include "srv0srv.h"
1130 /*********************************************************************//**
1131 Gets the current size of buffer buf_pool in bytes.
1132 @return size in bytes */
1133 @@ -681,6 +681,12 @@
1134 /*================*/
1135 const buf_block_t* block) /*!< in: pointer to the control block */
1137 + ut_a(srv_pass_corrupt_table || block);
1139 + if (srv_pass_corrupt_table && !block) {
1145 switch (buf_block_get_state(block)) {
1146 --- a/storage/innobase/include/dict0dict.h
1147 +++ b/storage/innobase/include/dict0dict.h
1148 @@ -1326,6 +1326,15 @@
1149 /*========================*/
1150 ulint space_id); /*!< in: space ID */
1152 +/*************************************************************************
1153 +set is_corrupt flag by space_id*/
1156 +dict_table_set_corrupt_by_space(
1157 +/*============================*/
1159 + ibool need_mutex);
1162 #include "dict0dict.ic"
1164 --- a/storage/innobase/include/dict0mem.h
1165 +++ b/storage/innobase/include/dict0mem.h
1167 the AUTOINC lock on this table. */
1169 /*----------------------*/
1171 #endif /* !UNIV_HOTBACKUP */
1174 --- a/storage/innobase/include/fil0fil.h
1175 +++ b/storage/innobase/include/fil0fil.h
1176 @@ -759,6 +759,19 @@
1177 fil_system_hash_nodes(void);
1178 /*========================*/
1180 +/*************************************************************************
1181 +functions to access is_corrupt flag of fil_space_t*/
1184 +fil_space_is_corrupt(
1185 +/*=================*/
1189 +fil_space_set_corrupt(
1190 +/*==================*/
1193 typedef struct fil_space_struct fil_space_t;
1196 --- a/storage/innobase/include/fut0fut.ic
1197 +++ b/storage/innobase/include/fut0fut.ic
1199 Created 12/13/1995 Heikki Tuuri
1200 ***********************************************************************/
1202 +#include "srv0srv.h"
1203 #include "sync0rw.h"
1204 #include "buf0buf.h"
1207 ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
1209 block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr);
1211 + if (srv_pass_corrupt_table && !block) {
1216 ptr = buf_block_get_frame(block) + addr.boffset;
1218 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
1219 --- a/storage/innobase/include/page0page.h
1220 +++ b/storage/innobase/include/page0page.h
1224 const page_t* page) /*!< in: page */
1225 - __attribute__((nonnull, pure));
1226 + __attribute__((pure));
1227 /************************************************************//**
1228 Gets the pointer to the next record on the page.
1229 @return pointer to next record */
1230 --- a/storage/innobase/include/page0page.ic
1231 +++ b/storage/innobase/include/page0page.ic
1234 const page_t* page) /*!< in: page */
1239 return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
1242 --- a/storage/innobase/include/page0zip.h
1243 +++ b/storage/innobase/include/page0zip.h
1245 const page_t* page, /*!< in: uncompressed page */
1246 dict_index_t* index, /*!< in: index of the B-tree node */
1247 mtr_t* mtr) /*!< in: mini-transaction, or NULL */
1248 - __attribute__((nonnull(1,2,3)));
1249 + __attribute__((nonnull(1,3)));
1251 /**********************************************************************//**
1252 Decompress a page. This function should tolerate errors on the compressed
1253 --- a/storage/innobase/include/srv0srv.h
1254 +++ b/storage/innobase/include/srv0srv.h
1256 extern ulint srv_adaptive_flushing_method;
1258 extern ulint srv_expand_import;
1259 +extern ulint srv_pass_corrupt_table;
1261 extern ulint srv_dict_size_limit;
1262 /*-------------------------------------------*/
1263 --- a/storage/innobase/page/page0zip.c
1264 +++ b/storage/innobase/page/page0zip.c
1265 @@ -1195,6 +1195,10 @@
1266 FILE* logfile = NULL;
1273 ut_a(page_is_comp(page));
1274 ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
1275 ut_ad(page_simple_validate_new((page_t*) page));
1276 --- a/storage/innobase/row/row0ins.c
1277 +++ b/storage/innobase/row/row0ins.c
1278 @@ -1341,6 +1341,12 @@
1279 const rec_t* rec = btr_pcur_get_rec(&pcur);
1280 const buf_block_t* block = btr_pcur_get_block(&pcur);
1282 + if (srv_pass_corrupt_table && !block) {
1283 + err = DB_CORRUPTION;
1288 if (page_rec_is_infimum(rec)) {
1291 --- a/storage/innobase/row/row0merge.c
1292 +++ b/storage/innobase/row/row0merge.c
1293 @@ -1245,6 +1245,13 @@
1295 if (UNIV_LIKELY(has_next)) {
1296 rec = btr_pcur_get_rec(&pcur);
1298 + if (srv_pass_corrupt_table && !rec) {
1299 + err = DB_CORRUPTION;
1304 offsets = rec_get_offsets(rec, clust_index, NULL,
1305 ULINT_UNDEFINED, &row_heap);
1307 --- a/storage/innobase/row/row0sel.c
1308 +++ b/storage/innobase/row/row0sel.c
1309 @@ -3919,6 +3919,13 @@
1310 /* PHASE 4: Look for matching records in a loop */
1312 rec = btr_pcur_get_rec(pcur);
1314 + if (srv_pass_corrupt_table && !rec) {
1315 + err = DB_CORRUPTION;
1316 + goto lock_wait_or_error;
1320 ut_ad(!!page_rec_is_comp(rec) == comp);
1321 #ifdef UNIV_SEARCH_DEBUG
1323 @@ -3996,7 +4003,13 @@
1324 if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
1327 - if (srv_force_recovery == 0 || moves_up == FALSE) {
1328 + if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
1329 + index->table->is_corrupt = TRUE;
1330 + fil_space_set_corrupt(index->table->space);
1333 + if ((srv_force_recovery == 0 || moves_up == FALSE)
1334 + && srv_pass_corrupt_table <= 1) {
1335 ut_print_timestamp(stderr);
1336 buf_page_print(page_align(rec), 0);
1338 @@ -4047,7 +4060,8 @@
1340 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
1342 - if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
1343 + if (UNIV_UNLIKELY(srv_force_recovery > 0)
1344 + || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) {
1345 if (!rec_validate(rec, offsets)
1346 || !btr_index_rec_validate(rec, index, FALSE)) {
1348 --- a/storage/innobase/srv/srv0srv.c
1349 +++ b/storage/innobase/srv/srv0srv.c
1351 UNIV_INTERN ulint srv_adaptive_flushing_method = 0; /* 0: native 1: estimate 2: keep_average */
1353 UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */
1354 +UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
1356 UNIV_INTERN ulint srv_dict_size_limit = 0;
1357 /*-------------------------------------------*/
1358 --- a/storage/innobase/srv/srv0start.c
1359 +++ b/storage/innobase/srv/srv0start.c
1360 @@ -2175,6 +2175,13 @@
1362 os_fast_mutex_free(&srv_os_test_mutex);
1364 + if (!srv_file_per_table_original_value
1365 + && srv_pass_corrupt_table) {
1366 + fprintf(stderr, "InnoDB: Warning:"
1367 + " The option innodb_file_per_table is disabled,"
1368 + " so using the option innodb_pass_corrupt_table doesn't make sense.\n");
1371 if (srv_print_verbose_log) {
1372 ut_print_timestamp(stderr);