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 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 @@ -1437,6 +1449,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 @@ -1460,6 +1479,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 @@ -1493,6 +1518,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 @@ -977,6 +1041,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 @@ -1190,6 +1262,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 @@ -2922,6 +3000,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 @@ -3630,6 +3713,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 @@ -1151,6 +1152,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 @@ -1945,6 +1951,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 @@ -2524,6 +2537,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 @@ -3198,6 +3218,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 @@ -3836,6 +3857,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 @@ -3877,6 +3899,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 @@ -3893,6 +3932,7 @@
415 if (recv_recovery_is_on()) {
416 /* Pages must be uncompressed for crash recovery. */
417 @@ -3902,8 +3942,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 @@ -1293,7 +1294,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 @@ -4367,6 +4368,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 @@ -4514,6 +4521,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 @@ -4706,6 +4719,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 @@ -5685,4 +5705,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 @@ -5277,6 +5280,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 @@ -5291,6 +5322,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 @@ -5791,3 +5824,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 @@ -1866,6 +1878,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 @@ -1979,6 +1996,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 @@ -2072,6 +2094,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 @@ -2098,7 +2125,7 @@
745 = fseg_inode_try_get(header, space, zip_size, mtr);
747 + ut_a(srv_pass_corrupt_table || inode);
751 @@ -3304,6 +3331,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 @@ -3551,6 +3583,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 @@ -3635,6 +3672,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 @@ -4011,6 +4011,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 /* Create buffers for packing the fields of a record. Why
801 table->reclength did not work here? Obviously, because char
802 fields when packed actually became 1 byte longer, when we also
803 @@ -4038,6 +4044,19 @@
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) {
811 + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
814 + share->ib_table = ib_table;
820 if (NULL == ib_table) {
821 if (is_part && retries < 10) {
823 @@ -5187,6 +5206,10 @@
825 ha_statistic_increment(&SSV::ha_write_count);
827 + if (share->ib_table->is_corrupt) {
828 + DBUG_RETURN(HA_ERR_CRASHED);
831 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
832 table->timestamp_field->set_time();
834 @@ -5403,6 +5426,10 @@
836 innobase_active_small();
838 + if (share->ib_table->is_corrupt) {
839 + DBUG_RETURN(HA_ERR_CRASHED);
842 DBUG_RETURN(error_result);
845 @@ -5580,6 +5607,10 @@
847 ha_statistic_increment(&SSV::ha_update_count);
849 + if (share->ib_table->is_corrupt) {
850 + DBUG_RETURN(HA_ERR_CRASHED);
853 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
854 table->timestamp_field->set_time();
856 @@ -5668,6 +5699,10 @@
858 innobase_active_small();
860 + if (share->ib_table->is_corrupt) {
861 + DBUG_RETURN(HA_ERR_CRASHED);
867 @@ -5689,6 +5724,10 @@
869 ha_statistic_increment(&SSV::ha_delete_count);
871 + if (share->ib_table->is_corrupt) {
872 + DBUG_RETURN(HA_ERR_CRASHED);
875 if (!prebuilt->upd_node) {
876 row_get_prebuilt_update_vector(prebuilt);
878 @@ -5715,6 +5754,10 @@
880 innobase_active_small();
882 + if (share->ib_table->is_corrupt) {
883 + DBUG_RETURN(HA_ERR_CRASHED);
889 @@ -5954,6 +5997,10 @@
891 ha_statistic_increment(&SSV::ha_read_key_count);
893 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
894 + DBUG_RETURN(HA_ERR_CRASHED);
897 index = prebuilt->index;
899 if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) {
900 @@ -6022,6 +6069,10 @@
901 ret = DB_UNSUPPORTED;
904 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
905 + DBUG_RETURN(HA_ERR_CRASHED);
911 @@ -6137,6 +6188,10 @@
913 DBUG_ENTER("change_active_index");
915 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
916 + DBUG_RETURN(HA_ERR_CRASHED);
919 ut_ad(user_thd == ha_thd());
920 ut_a(prebuilt->trx == thd_to_trx(user_thd));
922 @@ -6250,6 +6305,10 @@
924 DBUG_ENTER("general_fetch");
926 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
927 + DBUG_RETURN(HA_ERR_CRASHED);
930 ut_a(prebuilt->trx == thd_to_trx(user_thd));
932 innodb_srv_conc_enter_innodb(prebuilt->trx);
933 @@ -6259,6 +6318,10 @@
935 innodb_srv_conc_exit_innodb(prebuilt->trx);
937 + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
938 + DBUG_RETURN(HA_ERR_CRASHED);
944 @@ -7525,10 +7588,18 @@
946 update_thd(ha_thd());
948 + if (share->ib_table->is_corrupt) {
949 + DBUG_RETURN(HA_ERR_CRASHED);
952 /* Truncate the table in InnoDB */
954 error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
956 + if (share->ib_table->is_corrupt) {
957 + DBUG_RETURN(HA_ERR_CRASHED);
960 error = convert_error_code_to_mysql(error, prebuilt->table->flags,
963 @@ -8040,6 +8111,16 @@
964 return(ranges + (double) rows / (double) total_rows * time_for_scan);
969 +ha_innobase::is_corrupt() const
971 + if (share->ib_table)
972 + return ((bool)share->ib_table->is_corrupt);
977 /*********************************************************************//**
978 Calculates the key number used inside MySQL for an Innobase index. We will
979 first check the "index translation table" for a match of the index to get
980 @@ -8217,7 +8298,7 @@
981 ib_table = prebuilt->table;
983 if (flag & HA_STATUS_TIME) {
984 - if (called_from_analyze || innobase_stats_on_metadata) {
985 + if ((called_from_analyze || innobase_stats_on_metadata) && !share->ib_table->is_corrupt) {
986 /* In sql_show we call with this flag: update
987 then statistics so that they are up-to-date */
989 @@ -8517,10 +8598,18 @@
990 THD* thd, /*!< in: connection thread handle */
991 HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
993 + if (share->ib_table->is_corrupt) {
994 + return(HA_ADMIN_CORRUPT);
997 /* Simply call ::info() with all the flags */
998 info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
999 true /* called from analyze */);
1001 + if (share->ib_table->is_corrupt) {
1002 + return(HA_ADMIN_CORRUPT);
1008 @@ -8756,6 +8845,10 @@
1009 my_error(ER_QUERY_INTERRUPTED, MYF(0));
1012 + if (share->ib_table->is_corrupt) {
1013 + return(HA_ADMIN_CORRUPT);
1016 DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
1019 @@ -9526,6 +9619,10 @@
1023 + if (share->ib_table->is_corrupt) {
1024 + DBUG_RETURN(HA_ERR_CRASHED);
1027 if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) {
1028 ut_print_timestamp(stderr);
1030 @@ -11990,6 +12087,26 @@
1031 "dump file (if present). Disabled by default.",
1034 +const char *corrupt_table_action_names[]=
1038 + "salvage", /* 2 */
1041 +TYPELIB corrupt_table_action_typelib=
1043 + array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib",
1044 + corrupt_table_action_names, NULL
1046 +static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
1047 + PLUGIN_VAR_RQCMDARG,
1048 + "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, "
1049 + "when used with file_per_table. "
1050 + "All file io for the datafile after detected as corrupt are disabled, "
1051 + "except for the deletion.",
1052 + NULL, NULL, 0, &corrupt_table_action_typelib);
1054 static struct st_mysql_sys_var* innobase_system_variables[]= {
1055 MYSQL_SYSVAR(additional_mem_pool_size),
1056 MYSQL_SYSVAR(autoextend_increment),
1057 @@ -12083,6 +12200,7 @@
1059 MYSQL_SYSVAR(flush_checkpoint_debug),
1061 + MYSQL_SYSVAR(corrupt_table_action),
1065 --- a/storage/innobase/handler/ha_innodb.h
1066 +++ b/storage/innobase/handler/ha_innodb.h
1068 innodb_idx_translate_t idx_trans_tbl; /*!< index translation
1069 table between MySQL and
1071 + dict_table_t* ib_table;
1078 double read_time(uint index, uint ranges, ha_rows rows);
1079 + bool is_corrupt() const;
1081 int write_row(uchar * buf);
1082 int update_row(const uchar * old_data, uchar * new_data);
1083 --- a/storage/innobase/include/btr0btr.ic
1084 +++ b/storage/innobase/include/btr0btr.ic
1086 #include "mtr0mtr.h"
1087 #include "mtr0log.h"
1088 #include "page0zip.h"
1090 +#include "srv0srv.h"
1091 #define BTR_MAX_NODE_LEVEL 50 /*!< Maximum B-tree page level
1092 (not really a hard limit).
1093 Used in debug assertions
1095 block = buf_page_get_gen(space, zip_size, page_no, mode,
1096 NULL, BUF_GET, file, line, mtr);
1098 - if (mode != RW_NO_LATCH) {
1099 + ut_a(srv_pass_corrupt_table || block);
1101 + if (block && mode != RW_NO_LATCH) {
1103 buf_block_dbg_add_level(
1104 block, index != NULL && dict_index_is_ibuf(index)
1105 --- a/storage/innobase/include/buf0buf.h
1106 +++ b/storage/innobase/include/buf0buf.h
1107 @@ -1003,7 +1003,7 @@
1108 const buf_block_t* block) /*!< in: pointer to the control block */
1109 __attribute__((pure));
1110 #else /* UNIV_DEBUG */
1111 -# define buf_block_get_frame(block) (block)->frame
1112 +# define buf_block_get_frame(block) (block ? (block)->frame : 0)
1113 #endif /* UNIV_DEBUG */
1114 /*********************************************************************//**
1115 Gets the space id of a block.
1116 @@ -1450,6 +1450,7 @@
1117 0 if the block was never accessed
1118 in the buffer pool */
1121 # if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1122 ibool file_page_was_freed;
1123 /*!< this is set to TRUE when fsp
1124 --- a/storage/innobase/include/buf0buf.ic
1125 +++ b/storage/innobase/include/buf0buf.ic
1127 #include "buf0flu.h"
1128 #include "buf0lru.h"
1129 #include "buf0rea.h"
1131 +#include "srv0srv.h"
1132 /*********************************************************************//**
1133 Gets the current size of buffer buf_pool in bytes.
1134 @return size in bytes */
1135 @@ -637,6 +637,12 @@
1136 /*================*/
1137 const buf_block_t* block) /*!< in: pointer to the control block */
1139 + ut_a(srv_pass_corrupt_table || block);
1141 + if (srv_pass_corrupt_table && !block) {
1147 switch (buf_block_get_state(block)) {
1148 --- a/storage/innobase/include/dict0dict.h
1149 +++ b/storage/innobase/include/dict0dict.h
1150 @@ -1326,6 +1326,15 @@
1151 /*========================*/
1152 ulint space_id); /*!< in: space ID */
1154 +/*************************************************************************
1155 +set is_corrupt flag by space_id*/
1158 +dict_table_set_corrupt_by_space(
1159 +/*============================*/
1161 + ibool need_mutex);
1164 #include "dict0dict.ic"
1166 --- a/storage/innobase/include/dict0mem.h
1167 +++ b/storage/innobase/include/dict0mem.h
1169 the AUTOINC lock on this table. */
1171 /*----------------------*/
1173 #endif /* !UNIV_HOTBACKUP */
1176 --- a/storage/innobase/include/fil0fil.h
1177 +++ b/storage/innobase/include/fil0fil.h
1178 @@ -754,6 +754,19 @@
1179 fil_system_hash_nodes(void);
1180 /*========================*/
1182 +/*************************************************************************
1183 +functions to access is_corrupt flag of fil_space_t*/
1186 +fil_space_is_corrupt(
1187 +/*=================*/
1191 +fil_space_set_corrupt(
1192 +/*==================*/
1195 typedef struct fil_space_struct fil_space_t;
1198 --- a/storage/innobase/include/fut0fut.ic
1199 +++ b/storage/innobase/include/fut0fut.ic
1201 Created 12/13/1995 Heikki Tuuri
1202 ***********************************************************************/
1204 +#include "srv0srv.h"
1205 #include "sync0rw.h"
1206 #include "buf0buf.h"
1209 ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
1211 block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr);
1213 + if (srv_pass_corrupt_table && !block) {
1218 ptr = buf_block_get_frame(block) + addr.boffset;
1220 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
1221 --- a/storage/innobase/include/page0page.h
1222 +++ b/storage/innobase/include/page0page.h
1226 const page_t* page) /*!< in: page */
1227 - __attribute__((nonnull, pure));
1228 + __attribute__((pure));
1229 /************************************************************//**
1230 Gets the pointer to the next record on the page.
1231 @return pointer to next record */
1232 --- a/storage/innobase/include/page0page.ic
1233 +++ b/storage/innobase/include/page0page.ic
1236 const page_t* page) /*!< in: page */
1241 return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
1244 --- a/storage/innobase/include/page0zip.h
1245 +++ b/storage/innobase/include/page0zip.h
1247 const page_t* page, /*!< in: uncompressed page */
1248 dict_index_t* index, /*!< in: index of the B-tree node */
1249 mtr_t* mtr) /*!< in: mini-transaction, or NULL */
1250 - __attribute__((nonnull(1,2,3)));
1251 + __attribute__((nonnull(1,3)));
1253 /**********************************************************************//**
1254 Decompress a page. This function should tolerate errors on the compressed
1255 --- a/storage/innobase/include/srv0srv.h
1256 +++ b/storage/innobase/include/srv0srv.h
1258 extern ulint srv_adaptive_flushing_method;
1260 extern ulint srv_expand_import;
1261 +extern ulint srv_pass_corrupt_table;
1263 extern ulint srv_dict_size_limit;
1264 /*-------------------------------------------*/
1265 --- a/storage/innobase/page/page0zip.c
1266 +++ b/storage/innobase/page/page0zip.c
1267 @@ -1195,6 +1195,10 @@
1268 FILE* logfile = NULL;
1275 ut_a(page_is_comp(page));
1276 ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
1277 ut_ad(page_simple_validate_new((page_t*) page));
1278 --- a/storage/innobase/row/row0ins.c
1279 +++ b/storage/innobase/row/row0ins.c
1280 @@ -1341,6 +1341,12 @@
1281 const rec_t* rec = btr_pcur_get_rec(&pcur);
1282 const buf_block_t* block = btr_pcur_get_block(&pcur);
1284 + if (srv_pass_corrupt_table && !block) {
1285 + err = DB_CORRUPTION;
1290 if (page_rec_is_infimum(rec)) {
1293 --- a/storage/innobase/row/row0merge.c
1294 +++ b/storage/innobase/row/row0merge.c
1295 @@ -1245,6 +1245,13 @@
1297 if (UNIV_LIKELY(has_next)) {
1298 rec = btr_pcur_get_rec(&pcur);
1300 + if (srv_pass_corrupt_table && !rec) {
1301 + err = DB_CORRUPTION;
1306 offsets = rec_get_offsets(rec, clust_index, NULL,
1307 ULINT_UNDEFINED, &row_heap);
1309 --- a/storage/innobase/row/row0sel.c
1310 +++ b/storage/innobase/row/row0sel.c
1311 @@ -3912,6 +3912,13 @@
1312 /* PHASE 4: Look for matching records in a loop */
1314 rec = btr_pcur_get_rec(pcur);
1316 + if (srv_pass_corrupt_table && !rec) {
1317 + err = DB_CORRUPTION;
1318 + goto lock_wait_or_error;
1322 ut_ad(!!page_rec_is_comp(rec) == comp);
1323 #ifdef UNIV_SEARCH_DEBUG
1325 @@ -3989,7 +3996,13 @@
1326 if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
1329 - if (srv_force_recovery == 0 || moves_up == FALSE) {
1330 + if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
1331 + index->table->is_corrupt = TRUE;
1332 + fil_space_set_corrupt(index->table->space);
1335 + if ((srv_force_recovery == 0 || moves_up == FALSE)
1336 + && srv_pass_corrupt_table <= 1) {
1337 ut_print_timestamp(stderr);
1338 buf_page_print(page_align(rec), 0);
1340 @@ -4040,7 +4053,8 @@
1342 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
1344 - if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
1345 + if (UNIV_UNLIKELY(srv_force_recovery > 0)
1346 + || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) {
1347 if (!rec_validate(rec, offsets)
1348 || !btr_index_rec_validate(rec, index, FALSE)) {
1350 --- a/storage/innobase/srv/srv0srv.c
1351 +++ b/storage/innobase/srv/srv0srv.c
1353 UNIV_INTERN ulint srv_adaptive_flushing_method = 0; /* 0: native 1: estimate 2: keep_average */
1355 UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */
1356 +UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
1358 UNIV_INTERN ulint srv_dict_size_limit = 0;
1359 /*-------------------------------------------*/
1360 --- a/storage/innobase/srv/srv0start.c
1361 +++ b/storage/innobase/srv/srv0start.c
1362 @@ -2155,6 +2155,13 @@
1364 os_fast_mutex_free(&srv_os_test_mutex);
1366 + if (!srv_file_per_table_original_value
1367 + && srv_pass_corrupt_table) {
1368 + fprintf(stderr, "InnoDB: Warning:"
1369 + " The option innodb_file_per_table is disabled,"
1370 + " so using the option innodb_pass_corrupt_table doesn't make sense.\n");
1373 if (srv_print_verbose_log) {
1374 ut_print_timestamp(stderr);