summaryrefslogtreecommitdiff
path: root/storage/xtradb/fil/fil0fil.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/fil/fil0fil.c')
-rw-r--r--storage/xtradb/fil/fil0fil.c156
1 files changed, 145 insertions, 11 deletions
diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c
index 0139fa0cce5..a8520187013 100644
--- a/storage/xtradb/fil/fil0fil.c
+++ b/storage/xtradb/fil/fil0fil.c
@@ -3043,6 +3043,10 @@ fil_open_single_table_tablespace(
if (srv_expand_import
&& (space_id != id || space_flags != (flags & ~(~0 << DICT_TF_BITS)))) {
+ ibool file_is_corrupt = FALSE;
+ byte* buf3;
+ byte* descr_page;
+ ibool descr_is_corrupt = FALSE;
dulint old_id[31];
dulint new_id[31];
ulint root_page[31];
@@ -3052,16 +3056,37 @@ fil_open_single_table_tablespace(
ulint i;
int len;
ib_uint64_t current_lsn;
- ulint size_low, size_high, size;
- ib_int64_t size_bytes;
+ ulint size_low, size_high, size, free_limit;
+ ib_int64_t size_bytes, free_limit_bytes;
dict_table_t* table;
dict_index_t* index;
fil_system_t* system;
fil_node_t* node = NULL;
fil_space_t* space;
+ buf3 = ut_malloc(2 * UNIV_PAGE_SIZE);
+ descr_page = ut_align(buf3, UNIV_PAGE_SIZE);
+
current_lsn = log_get_lsn();
+ /* check the header page's consistency */
+ if (buf_page_is_corrupted(page,
+ dict_table_flags_to_zip_size(space_flags))) {
+ fprintf(stderr, "InnoDB: page 0 of %s seems corrupt.\n", filepath);
+ file_is_corrupt = TRUE;
+ descr_is_corrupt = TRUE;
+ }
+
+ /* store as first descr page */
+ memcpy(descr_page, page, UNIV_PAGE_SIZE);
+
+ /* get free limit (page number) of the table space */
+/* these should be same to the definition in fsp0fsp.c */
+#define FSP_HEADER_OFFSET FIL_PAGE_DATA
+#define FSP_FREE_LIMIT 12
+ free_limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + page);
+ free_limit_bytes = (ib_int64_t)free_limit * (ib_int64_t)UNIV_PAGE_SIZE;
+
/* overwrite fsp header */
fsp_header_init_fields(page, id, flags);
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, id);
@@ -3086,6 +3111,12 @@ fil_open_single_table_tablespace(
size_bytes = (((ib_int64_t)size_high) << 32)
+ (ib_int64_t)size_low;
+ if (size_bytes < free_limit_bytes) {
+ free_limit_bytes = size_bytes;
+ fprintf(stderr, "InnoDB: free limit of %s is larger than its real size.\n", filepath);
+ file_is_corrupt = TRUE;
+ }
+
/* get cruster index information */
table = dict_table_get_low(name);
index = dict_table_get_first_index(table);
@@ -3107,16 +3138,19 @@ fil_open_single_table_tablespace(
info_file_path, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success);
if (!success) {
fprintf(stderr, "InnoDB: cannot open %s\n", info_file_path);
+ file_is_corrupt = TRUE;
goto skip_info;
}
success = os_file_read(info_file, page, 0, 0, UNIV_PAGE_SIZE);
if (!success) {
fprintf(stderr, "InnoDB: cannot read %s\n", info_file_path);
+ file_is_corrupt = TRUE;
goto skip_info;
}
if (mach_read_from_4(page) != 0x78706f72UL
|| mach_read_from_4(page + 4) != 0x74696e66UL) {
fprintf(stderr, "InnoDB: %s seems not to be a correct .exp file\n", info_file_path);
+ file_is_corrupt = TRUE;
goto skip_info;
}
@@ -3153,20 +3187,29 @@ skip_info:
fprintf(stderr, "InnoDB: Progress in %%:");
- for (offset = 0; offset < size_bytes; offset += UNIV_PAGE_SIZE) {
+ for (offset = 0; offset < free_limit_bytes; offset += UNIV_PAGE_SIZE) {
ulint checksum_field;
ulint old_checksum_field;
+ ibool page_is_corrupt;
success = os_file_read(file, page,
(ulint)(offset & 0xFFFFFFFFUL),
(ulint)(offset >> 32), UNIV_PAGE_SIZE);
- /* skip inconsistent pages, it may be free page. */
+ page_is_corrupt = FALSE;
+
+ /* check consistency */
if (memcmp(page + FIL_PAGE_LSN + 4,
page + UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) {
- goto skip_write;
+ page_is_corrupt = TRUE;
+ }
+
+ if (mach_read_from_4(page + FIL_PAGE_OFFSET)
+ != offset / UNIV_PAGE_SIZE) {
+
+ page_is_corrupt = TRUE;
}
checksum_field = mach_read_from_4(page
@@ -3182,7 +3225,7 @@ skip_info:
&& old_checksum_field
!= buf_calc_page_old_checksum(page)) {
- goto skip_write;
+ page_is_corrupt = TRUE;
}
if (!srv_fast_checksum
@@ -3191,7 +3234,7 @@ skip_info:
&& checksum_field
!= buf_calc_page_new_checksum(page)) {
- goto skip_write;
+ page_is_corrupt = TRUE;
}
if (srv_fast_checksum
@@ -3202,6 +3245,77 @@ skip_info:
&& checksum_field
!= buf_calc_page_new_checksum(page)) {
+ page_is_corrupt = TRUE;
+ }
+
+ /* if it is free page, inconsistency is acceptable */
+ if (!offset) {
+ /* header page*/
+ /* it should be overwritten already */
+ ut_a(!page_is_corrupt);
+
+ } else if (!((offset / UNIV_PAGE_SIZE) % UNIV_PAGE_SIZE)) {
+ /* descr page (not header) */
+ if (page_is_corrupt) {
+ file_is_corrupt = TRUE;
+ descr_is_corrupt = TRUE;
+ } else {
+ ut_a(fil_page_get_type(page) == FIL_PAGE_TYPE_XDES);
+ descr_is_corrupt = FALSE;
+ }
+
+ /* store as descr page */
+ memcpy(descr_page, page, UNIV_PAGE_SIZE);
+
+ } else if (descr_is_corrupt) {
+ /* unknown state of the page */
+ if (page_is_corrupt) {
+ file_is_corrupt = TRUE;
+ }
+
+ } else {
+ /* check free page or not */
+ /* These definitions should be same to fsp0fsp.c */
+#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
+
+#define XDES_BITMAP (FLST_NODE_SIZE + 12)
+#define XDES_BITS_PER_PAGE 2
+#define XDES_FREE_BIT 0
+#define XDES_SIZE \
+ (XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
+#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
+
+ /*descr = descr_page + XDES_ARR_OFFSET + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset)*/
+ /*xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)*/
+ byte* descr;
+ ulint index;
+ ulint byte_index;
+ ulint bit_index;
+
+ descr = descr_page + XDES_ARR_OFFSET
+ + XDES_SIZE * (ut_2pow_remainder((offset / UNIV_PAGE_SIZE), UNIV_PAGE_SIZE) / FSP_EXTENT_SIZE);
+
+ index = XDES_FREE_BIT + XDES_BITS_PER_PAGE * ((offset / UNIV_PAGE_SIZE) % FSP_EXTENT_SIZE);
+ byte_index = index / 8;
+ bit_index = index % 8;
+
+ if (ut_bit_get_nth(mach_read_from_1(descr + XDES_BITMAP + byte_index), bit_index)) {
+ /* free page */
+ if (page_is_corrupt) {
+ goto skip_write;
+ }
+ } else {
+ /* not free */
+ if (page_is_corrupt) {
+ file_is_corrupt = TRUE;
+ }
+ }
+ }
+
+ if (page_is_corrupt) {
+ fprintf(stderr, " [errp:%lld]", offset / UNIV_PAGE_SIZE);
+
+ /* cannot treat corrupt page */
goto skip_write;
}
@@ -3294,11 +3408,11 @@ skip_info:
}
skip_write:
- if (size_bytes
- && ((ib_int64_t)((offset + UNIV_PAGE_SIZE) * 100) / size_bytes)
- != ((offset * 100) / size_bytes)) {
+ if (free_limit_bytes
+ && ((ib_int64_t)((offset + UNIV_PAGE_SIZE) * 100) / free_limit_bytes)
+ != ((offset * 100) / free_limit_bytes)) {
fprintf(stderr, " %lu",
- (ulong)((ib_int64_t)((offset + UNIV_PAGE_SIZE) * 100) / size_bytes));
+ (ulong)((ib_int64_t)((offset + UNIV_PAGE_SIZE) * 100) / free_limit_bytes));
}
}
@@ -3379,6 +3493,26 @@ skip_write:
node->size = size;
}
mutex_exit(&(system->mutex));
+
+ ut_free(buf3);
+
+ if (file_is_corrupt) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: file ",
+ stderr);
+ ut_print_filename(stderr, filepath);
+ fprintf(stderr, " seems to be corrupt.\n"
+ "InnoDB: anyway, all not corrupt pages were tried to be converted to salvage.\n"
+ "InnoDB: ##### CAUTION #####\n"
+ "InnoDB: ## The .ibd must cause to crash InnoDB, though re-import would seem to be succeeded.\n"
+ "InnoDB: ## If you don't have knowledge about salvaging data from .ibd, you should not use the file.\n"
+ "InnoDB: ###################\n");
+ success = FALSE;
+
+ ut_free(buf2);
+
+ goto func_exit;
+ }
}
ut_free(buf2);