summaryrefslogtreecommitdiff
path: root/innobase/log/log0recv.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/log/log0recv.c')
-rw-r--r--innobase/log/log0recv.c249
1 files changed, 161 insertions, 88 deletions
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index 53f75c176ea..1223f9b6041 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -58,12 +58,16 @@ yet: the variable name is misleading */
ibool recv_no_ibuf_operations = FALSE;
-/* the following counter is used to decide when to print info on
+/* The following counter is used to decide when to print info on
log scan */
ulint recv_scan_print_counter = 0;
ibool recv_is_from_backup = FALSE;
+ibool recv_is_making_a_backup = FALSE;
+ulint recv_previous_parsed_rec_type = 999999;
+ulint recv_previous_parsed_rec_offset = 0;
+ulint recv_previous_parsed_rec_is_multi = 0;
/************************************************************
Creates the recovery system. */
@@ -124,6 +128,8 @@ recv_sys_init(
recv_sys->last_block = ut_align(recv_sys->last_block_buf_start,
OS_FILE_LOG_BLOCK_SIZE);
+ recv_sys->found_corrupt_log = FALSE;
+
mutex_exit(&(recv_sys->mutex));
}
@@ -569,9 +575,9 @@ recv_read_cp_info_for_backup(
}
/**********************************************************
-Checks the 1-byte checksum to the trailer checksum field of a log block.
-We also accept a log block in the old format where the checksum field
-contained the highest byte of the log block number. */
+Checks the 4-byte checksum to the trailer checksum field of a log block.
+We also accept a log block in the old format < InnoDB-3.23.52 where the
+checksum field contains the log block number. */
static
ibool
log_block_checksum_is_ok_or_old_format(
@@ -580,29 +586,12 @@ log_block_checksum_is_ok_or_old_format(
format of InnoDB version < 3.23.52 */
byte* block) /* in: pointer to a log block */
{
- ulint i;
- ulint sum;
-
- sum = 1;
-
- for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
- sum += (ulint)(*(block + i));
- }
-
-/* printf("Checksum %lu, byte %lu\n", 0xFF & sum,
- mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- - LOG_BLOCK_TRL_CHECKSUM));
-*/
- if (mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- - LOG_BLOCK_TRL_CHECKSUM)
- == (0xFF & sum)) {
+ if (log_block_calc_checksum(block) == log_block_get_checksum(block)) {
return(TRUE);
}
- if (((0xFF000000 & log_block_get_hdr_no(block)) >> 24)
- == mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- - LOG_BLOCK_TRL_CHECKSUM)) {
+ if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) {
/* We assume the log block is in the format of
InnoDB version < 3.23.52 and the block is ok */
@@ -649,23 +638,20 @@ recv_scan_log_seg_for_backup(
/* fprintf(stderr, "Log block header no %lu\n", no); */
- if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block)
- || no != log_block_convert_lsn_to_no(*scanned_lsn)
+ if (no != log_block_convert_lsn_to_no(*scanned_lsn)
|| !log_block_checksum_is_ok_or_old_format(log_block)) {
/*
printf(
-"Log block n:o %lu, trailer n:o %lu, scanned lsn n:o %lu\n",
- no, log_block_get_trl_no(log_block),
- log_block_convert_lsn_to_no(*scanned_lsn));
+"Log block n:o %lu, scanned lsn n:o %lu\n",
+ no, log_block_convert_lsn_to_no(*scanned_lsn));
*/
/* Garbage or an incompletely written log block */
log_block += OS_FILE_LOG_BLOCK_SIZE;
/*
printf(
-"Next log block n:o %lu, trailer n:o %lu\n",
- log_block_get_hdr_no(log_block),
- log_block_get_trl_no(log_block));
+"Next log block n:o %lu\n",
+ log_block_get_hdr_no(log_block));
*/
break;
}
@@ -788,14 +774,8 @@ recv_parse_or_apply_log_rec_body(
new_ptr = mlog_parse_string(ptr, end_ptr, page);
} else {
new_ptr = NULL;
-
- fprintf(stderr,
- "InnoDB: WARNING: the log file may have been corrupt and it\n"
- "InnoDB: is possible that the log scan did not proceed\n"
- "InnoDB: far enough in recovery. Please run CHECK TABLE\n"
- "InnoDB: on your InnoDB tables to check that they are ok!\n"
- "InnoDB: Corrupt log record type %lu\n",
- (ulint)type);
+
+ recv_sys->found_corrupt_log = TRUE;
}
ut_ad(!page || new_ptr);
@@ -1399,18 +1379,30 @@ recv_apply_log_recs_for_backup(
OS_FILE_OPEN,
OS_FILE_READ_WRITE,
&success);
- ut_a(success);
+ if (!success) {
+ printf(
+"InnoDB: Error: cannot open %lu'th data file %s\n", nth_file);
+
+ exit(1);
+ }
}
recv_addr = recv_get_fil_addr_struct(0, i);
if (recv_addr != NULL) {
- os_file_read(data_file, page,
+ success = os_file_read(data_file, page,
(nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFF,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE);
+ if (!success) {
+ printf(
+"InnoDB: Error: cannot read page no %lu from %lu'th data file %s\n",
+ nth_page_in_file, nth_file);
+ exit(1);
+ }
+
/* We simulate a page read made by the buffer pool,
to make sure recovery works ok. We must init the
block corresponding to buf_pool->frame_zero
@@ -1425,12 +1417,19 @@ recv_apply_log_recs_for_backup(
mach_read_from_8(page + FIL_PAGE_LSN),
0, i);
- os_file_write(data_files[nth_file],
+ success = os_file_write(data_files[nth_file],
data_file, page,
(nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFF,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE);
+ if (!success) {
+ printf(
+"InnoDB: Error: cannot write page no %lu to %lu'th data file %s\n",
+ nth_page_in_file, nth_file);
+
+ exit(1);
+ }
}
if ((100 * i) / n_pages_total
@@ -1679,29 +1678,16 @@ recv_parse_log_rec(
new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space,
page_no);
-
- /* If the operating system writes to the log complete 512-byte
- blocks, we should not get the warnings below in recovery.
- A warning means that the header and the trailer appeared ok
- in a 512-byte block, but in the middle there was something wrong.
- TODO: (1) add similar warnings in the case there is an incompletely
- written log record which does not extend to the boundary of a
- 512-byte block. (2) Add a checksum to a log block. */
-
if (!new_ptr) {
+
return(0);
}
/* Check that space id and page_no are sensible */
if (*space != 0 || *page_no > 0x8FFFFFFF) {
- fprintf(stderr,
- "InnoDB: WARNING: the log file may have been corrupt and it\n"
- "InnoDB: is possible that the log scan did not proceed\n"
- "InnoDB: far enough in recovery. Please run CHECK TABLE\n"
- "InnoDB: on your InnoDB tables to check that they are ok!\n"
- "InnoDB: Corrupt log record type %lu, space id %lu, page no %lu\n",
- (ulint)(*type), *space, *page_no);
+
+ recv_sys->found_corrupt_log = TRUE;
return(0);
}
@@ -1766,14 +1752,70 @@ recv_check_incomplete_log_recs(
}
/***********************************************************
+Prints diagnostic info of corrupt log. */
+static
+void
+recv_report_corrupt_log(
+/*====================*/
+ byte* ptr, /* in: pointer to corrupt log record */
+ byte type, /* in: type of the record */
+ ulint space, /* in: space id, this may also be garbage */
+ ulint page_no)/* in: page number, this may also be garbage */
+{
+ char* err_buf;
+
+ fprintf(stderr,
+"InnoDB: ############### CORRUPT LOG RECORD FOUND\n"
+"InnoDB: Log record type %lu, space id %lu, page number %lu\n"
+"InnoDB: Log parsing proceeded successfully up to %lu %lu\n",
+ (ulint)type, space, page_no,
+ ut_dulint_get_high(recv_sys->recovered_lsn),
+ ut_dulint_get_low(recv_sys->recovered_lsn));
+
+ err_buf = ut_malloc(1000000);
+
+ fprintf(stderr,
+"InnoDB: Previous log record type %lu, is multi %lu\n"
+"InnoDB: Recv offset %lu, prev %lu\n",
+ recv_previous_parsed_rec_type,
+ recv_previous_parsed_rec_is_multi,
+ ptr - recv_sys->buf,
+ recv_previous_parsed_rec_offset);
+
+ if ((ulint)(ptr - recv_sys->buf + 100)
+ > recv_previous_parsed_rec_offset
+ && (ulint)(ptr - recv_sys->buf + 100
+ - recv_previous_parsed_rec_offset)
+ < 200000) {
+
+ ut_sprintf_buf(err_buf,
+ recv_sys->buf + recv_previous_parsed_rec_offset - 100,
+ ptr - recv_sys->buf + 200 -
+ recv_previous_parsed_rec_offset);
+ fprintf(stderr,
+"InnoDB: Hex dump of corrupt log starting 100 bytes before the start\n"
+"InnoDB: of the previous log rec,\n"
+"InnoDB: and ending 100 bytes after the start of the corrupt rec:\n%s\n",
+ err_buf);
+ }
+
+ ut_free(err_buf);
+
+ fprintf(stderr,
+ "InnoDB: WARNING: the log file may have been corrupt and it\n"
+ "InnoDB: is possible that the log scan did not proceed\n"
+ "InnoDB: far enough in recovery! Please run CHECK TABLE\n"
+ "InnoDB: on your InnoDB tables to check that they are ok!\n");
+}
+
+/***********************************************************
Parses log records from a buffer and stores them to a hash table to wait
merging to file pages. */
static
ibool
recv_parse_log_recs(
/*================*/
- /* out: TRUE if the hash table of parsed log
- records became full */
+ /* out: currently always returns FALSE */
ibool store_to_hash) /* in: TRUE if the records should be stored
to the hash table; this is set to FALSE if just
debug checking is needed */
@@ -1812,8 +1854,13 @@ loop:
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
- if (len == 0) {
+ if (len == 0 || recv_sys->found_corrupt_log) {
+ if (recv_sys->found_corrupt_log) {
+ recv_report_corrupt_log(ptr,
+ type, space, page_no);
+ }
+
return(FALSE);
}
@@ -1828,6 +1875,10 @@ loop:
return(FALSE);
}
+ recv_previous_parsed_rec_type = (ulint)type;
+ recv_previous_parsed_rec_offset = recv_sys->recovered_offset;
+ recv_previous_parsed_rec_is_multi = 0;
+
recv_sys->recovered_offset += len;
recv_sys->recovered_lsn = new_recovered_lsn;
@@ -1851,9 +1902,10 @@ loop:
#ifdef UNIV_LOG_DEBUG
recv_check_incomplete_log_recs(ptr, len);
#endif
- recv_update_replicate(type, space, page_no, body,
+/* recv_update_replicate(type, space, page_no, body,
ptr + len);
recv_compare_replicate(space, page_no);
+*/
}
} else {
/* Check that all the records associated with the single mtr
@@ -1865,19 +1917,32 @@ loop:
for (;;) {
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
- if (len == 0) {
+ if (len == 0 || recv_sys->found_corrupt_log) {
- return(FALSE);
+ if (recv_sys->found_corrupt_log) {
+
+ recv_report_corrupt_log(ptr,
+ type, space, page_no);
+ }
+
+ return(FALSE);
}
+ recv_previous_parsed_rec_type = (ulint)type;
+ recv_previous_parsed_rec_offset
+ = recv_sys->recovered_offset + total_len;
+ recv_previous_parsed_rec_is_multi = 1;
+
if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) {
/* In debug checking, update a replicate page
according to the log record */
#ifdef UNIV_LOG_DEBUG
recv_check_incomplete_log_recs(ptr, len);
#endif
+/*
recv_update_replicate(type, space, page_no,
body, ptr + len);
+*/
}
if (log_debug_writes) {
@@ -1919,6 +1984,12 @@ loop:
old_lsn = recv_sys->recovered_lsn;
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
+ if (recv_sys->found_corrupt_log) {
+
+ recv_report_corrupt_log(ptr,
+ type, space, page_no);
+ }
+
ut_a(len != 0);
ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG));
@@ -1941,7 +2012,7 @@ loop:
page has become identical with the original
page */
- recv_compare_replicate(space, page_no);
+/* recv_compare_replicate(space, page_no); */
}
ptr += len;
@@ -2095,32 +2166,19 @@ recv_scan_log_recs(
/* fprintf(stderr, "Log block header no %lu\n", no); */
- if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block)
- || no != log_block_convert_lsn_to_no(scanned_lsn)
+ if (no != log_block_convert_lsn_to_no(scanned_lsn)
|| !log_block_checksum_is_ok_or_old_format(log_block)) {
- if ((no & 0xFFFFFF) == log_block_get_trl_no(log_block)
- && no == log_block_convert_lsn_to_no(scanned_lsn)
+ if (no == log_block_convert_lsn_to_no(scanned_lsn)
&& !log_block_checksum_is_ok_or_old_format(
log_block)) {
fprintf(stderr,
"InnoDB: Log block no %lu at lsn %lu %lu has\n"
-"InnoDB: ok header and trailer, but checksum field contains %lu\n",
- no, ut_dulint_get_high(scanned_lsn),
- ut_dulint_get_low(scanned_lsn),
- mach_read_from_1(log_block
- + OS_FILE_LOG_BLOCK_SIZE
- - LOG_BLOCK_TRL_CHECKSUM));
- }
-
- if ((no & 0xFFFFFF)
- != log_block_get_trl_no(log_block)) {
- fprintf(stderr,
-"InnoDB: Log block with header no %lu at lsn %lu %lu has\n"
-"InnoDB: trailer no %lu\n",
+"InnoDB: ok header, but checksum field contains %lu, should be %lu\n",
no, ut_dulint_get_high(scanned_lsn),
ut_dulint_get_low(scanned_lsn),
- log_block_get_trl_no(log_block));
+ log_block_get_checksum(log_block),
+ log_block_calc_checksum(log_block));
}
/* Garbage or an incompletely written log block */
@@ -2192,11 +2250,14 @@ recv_scan_log_recs(
>= RECV_PARSING_BUF_SIZE) {
fprintf(stderr,
"InnoDB: Error: log parsing buffer overflow. Recovery may have failed!\n");
- finished = TRUE;
+
+ recv_sys->found_corrupt_log = TRUE;
+
+ } else if (!recv_sys->found_corrupt_log) {
+ more_data = recv_sys_add_to_parsing_buf(
+ log_block, scanned_lsn);
}
- more_data = recv_sys_add_to_parsing_buf(log_block,
- scanned_lsn);
recv_sys->scanned_lsn = scanned_lsn;
recv_sys->scanned_checkpoint_no =
log_block_get_checkpoint_no(log_block);
@@ -2213,7 +2274,8 @@ recv_scan_log_recs(
*group_scanned_lsn = scanned_lsn;
- if (recv_needed_recovery || recv_is_from_backup) {
+ if (recv_needed_recovery
+ || (recv_is_from_backup && !recv_is_making_a_backup)) {
recv_scan_print_counter++;
if (finished || (recv_scan_print_counter % 80 == 0)) {
@@ -2225,7 +2287,7 @@ recv_scan_log_recs(
}
}
- if (more_data) {
+ if (more_data && !recv_sys->found_corrupt_log) {
/* Try to parse more log records */
recv_parse_log_recs(store_to_hash);
@@ -2602,6 +2664,17 @@ recv_recovery_from_checkpoint_finish(void)
trx_sys_print_mysql_binlog_offset();
}
+ if (recv_sys->found_corrupt_log) {
+
+ fprintf(stderr,
+ "InnoDB: WARNING: the log file may have been corrupt and it\n"
+ "InnoDB: is possible that the log scan or parsing did not proceed\n"
+ "InnoDB: far enough in recovery. Please run CHECK TABLE\n"
+ "InnoDB: on your InnoDB tables to check that they are ok!\n"
+ "InnoDB: It may be safest to recover your InnoDB database from\n"
+ "InnoDB: a backup!\n");
+ }
+
/* Free the resources of the recovery system */
recv_recovery_on = FALSE;