diff options
Diffstat (limited to 'innobase/log/log0recv.c')
-rw-r--r-- | innobase/log/log0recv.c | 147 |
1 files changed, 129 insertions, 18 deletions
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index c31719f7bb0..53f75c176ea 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -568,6 +568,55 @@ recv_read_cp_info_for_backup( return(TRUE); } +/********************************************************** +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. */ +static +ibool +log_block_checksum_is_ok_or_old_format( +/*===================================*/ + /* out: TRUE if ok, or if the log block may be in the + 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)) { + + 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)) { + + /* We assume the log block is in the format of + InnoDB version < 3.23.52 and the block is ok */ +/* + fprintf(stderr, +"InnoDB: Scanned old format < InnoDB-3.23.52 log block number %lu\n", + log_block_get_hdr_no(block)); +*/ + return(TRUE); + } + + return(FALSE); +} + /*********************************************************************** Scans the log segment and n_bytes_scanned is set to the length of valid log scanned. */ @@ -598,12 +647,13 @@ recv_scan_log_seg_for_backup( no = log_block_get_hdr_no(log_block); - /* fprintf(stderr, "Log block header no %lu\n", no); */ +/* fprintf(stderr, "Log block header no %lu\n", no); */ - if (no != log_block_get_trl_no(log_block) - || no != log_block_convert_lsn_to_no(*scanned_lsn)) { - -/* printf( + if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) + || 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)); @@ -611,8 +661,8 @@ recv_scan_log_seg_for_backup( /* Garbage or an incompletely written log block */ log_block += OS_FILE_LOG_BLOCK_SIZE; - -/* printf( +/* + 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)); @@ -629,11 +679,11 @@ recv_scan_log_seg_for_backup( /* Garbage from a log buffer flush which was made before the most recent database recovery */ - +/* printf("Scanned cp n:o %lu, block cp n:o %lu\n", *scanned_checkpoint_no, log_block_get_checkpoint_no(log_block)); - +*/ break; } @@ -1011,7 +1061,7 @@ recv_recover_page( page_lsn = page_newest_lsn; } } else { - /* In recovery from a backup we do not use the buffer + /* In recovery from a backup we do not really use the buffer pool */ page_newest_lsn = ut_dulint_zero; @@ -1361,6 +1411,14 @@ recv_apply_log_recs_for_backup( nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), UNIV_PAGE_SIZE); + /* 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 + (== page) */ + + buf_page_init_for_backup_restore(0, i, + buf_block_align(page)); + recv_recover_page(TRUE, FALSE, page, 0, i); buf_flush_init_for_writing(page, @@ -2037,8 +2095,33 @@ recv_scan_log_recs( /* fprintf(stderr, "Log block header no %lu\n", no); */ - if (no != log_block_get_trl_no(log_block) - || no != log_block_convert_lsn_to_no(scanned_lsn)) { + if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) + || 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) + && !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", + no, ut_dulint_get_high(scanned_lsn), + ut_dulint_get_low(scanned_lsn), + log_block_get_trl_no(log_block)); + } /* Garbage or an incompletely written log block */ @@ -2241,6 +2324,7 @@ recv_recovery_from_checkpoint_start( dulint archived_lsn; ulint capacity; byte* buf; + byte log_hdr_buf[LOG_FILE_HDR_SIZE]; ulint err; ut_ad((type != LOG_CHECKPOINT) @@ -2288,6 +2372,33 @@ recv_recovery_from_checkpoint_start( checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO); archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN); + /* Read the first log file header to print a note if this is + a recovery from a restored InnoDB Hot Backup */ + + fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, max_cp_group->space_id, + 0, 0, LOG_FILE_HDR_SIZE, + log_hdr_buf, max_cp_group); + + if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, + "ibbackup", ut_strlen("ibbackup"))) { + /* This log file was created by ibbackup --restore: print + a note to the user about it */ + + fprintf(stderr, + "InnoDB: The log file was created by ibbackup --restore at\n" + "InnoDB: %s\n", log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP); + + /* Wipe over the label now */ + + ut_memcpy(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, + " ", 4); + /* Write to the log file to wipe over the label */ + fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, + max_cp_group->space_id, + 0, 0, OS_FILE_LOG_BLOCK_SIZE, + log_hdr_buf, max_cp_group); + } + group = UT_LIST_GET_FIRST(log_sys->log_groups); while (group) { @@ -2471,7 +2582,7 @@ recv_recovery_from_checkpoint_finish(void) /* Rollback the uncommitted transactions which have no user session */ if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) { - trx_rollback_all_without_sess(); + trx_rollback_or_clean_all_without_sess(); } /* Apply the hashed log records to the respective file pages */ @@ -2487,6 +2598,7 @@ recv_recovery_from_checkpoint_finish(void) } if (recv_needed_recovery) { + trx_sys_print_mysql_master_log_pos(); trx_sys_print_mysql_binlog_offset(); } @@ -2614,10 +2726,9 @@ recv_reset_log_files_for_backup( /* We pretend there is a checkpoint at lsn + LOG_BLOCK_HDR_SIZE */ - log_reset_first_header_and_checkpoint(buf, - ut_dulint_add(lsn, LOG_BLOCK_HDR_SIZE)); + log_reset_first_header_and_checkpoint(buf, lsn); - log_block_init(buf + LOG_FILE_HDR_SIZE, lsn); + log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn); log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE, LOG_BLOCK_HDR_SIZE); sprintf(name, "%sib_logfile%lu", log_dir, 0); @@ -2754,7 +2865,7 @@ ask_again: if (ut_dulint_cmp(recv_sys->parse_start_lsn, start_lsn) < 0) { fprintf(stderr, "InnoDB: Archive log file %s starts from too big a lsn\n", - name); + name); return(TRUE); } @@ -2765,7 +2876,7 @@ ask_again: fprintf(stderr, "InnoDB: Archive log file %s starts from a wrong lsn\n", - name); + name); return(TRUE); } |