diff options
-rw-r--r-- | innobase/buf/buf0buf.c | 56 | ||||
-rw-r--r-- | innobase/buf/buf0flu.c | 6 | ||||
-rw-r--r-- | innobase/include/buf0buf.h | 10 | ||||
-rw-r--r-- | innobase/log/log0recv.c | 6 |
4 files changed, 62 insertions, 16 deletions
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 34fbc5b9f98..0046a3761a6 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -204,7 +204,28 @@ ulint buf_dbg_counter = 0; /* This is used to insert validation ibool buf_debug_prints = FALSE; /* If this is set TRUE, the program prints info whenever read-ahead or flush occurs */ - + +/************************************************************************ +Calculates a page checksum which is stored to the page when it is written +to a file. Note that we must be careful to calculate the same value +on 32-bit and 64-bit architectures. */ + +ulint +buf_calc_page_checksum( +/*===================*/ + /* out: checksum */ + byte* page) /* in: buffer page */ +{ + ulint checksum; + + checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN); + + ut_fold_binary(page + FIL_PAGE_DATA, UNIV_PAGE_SIZE - FIL_PAGE_DATA + - FIL_PAGE_END_LSN); + checksum = checksum & 0xFFFFFFFF; + + return(checksum); +} + /************************************************************************ Initializes a buffer control block when the buf_pool is created. */ static @@ -1171,12 +1192,36 @@ buf_page_io_complete( dulint id; dict_index_t* index; ulint io_type; + ulint checksum; ut_ad(block); io_type = block->io_fix; if (io_type == BUF_IO_READ) { + checksum = buf_calc_page_checksum(block->frame); + + /* From version 3.23.38 up we store the page checksum + to the 4 upper bytes of the page end lsn field */ + + if ((mach_read_from_4(block->frame + FIL_PAGE_LSN + 4) + != mach_read_from_4(block->frame + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN + 4)) + || (checksum != mach_read_from_4(block->frame + + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN) + && mach_read_from_4(block->frame + FIL_PAGE_LSN) + != mach_read_from_4(block->frame + + UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN))) { + fprintf(stderr, + "InnoDB: Database page corruption or a failed\n" + "InnoDB: file read of page %lu.\n", block->offset); + fprintf(stderr, + "InnoDB: You may have to recover from a backup.\n"); + exit(1); + } + if (recv_recovery_is_on()) { recv_recover_page(TRUE, block->frame, block->space, block->offset); @@ -1208,17 +1253,8 @@ buf_page_io_complete( ut_ad(buf_pool->n_pend_reads > 0); buf_pool->n_pend_reads--; buf_pool->n_pages_read++; -/* - if (0 != ut_dulint_cmp( - mach_read_from_8(block->frame + FIL_PAGE_LSN), - mach_read_from_8(block->frame + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN))) { - printf("DB error: file page corrupted!\n"); - ut_error; - } -*/ rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ); rw_lock_x_unlock_gen(&(block->read_lock), BUF_IO_READ); diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index 443256cca34..90bdde1ebc6 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -222,6 +222,12 @@ buf_flush_write_block_low( mach_write_to_8(block->frame + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN, block->newest_modification); + /* We overwrite the first 4 bytes of the end lsn field to store + a page checksum */ + + mach_write_to_4(block->frame + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN, + buf_calc_page_checksum(block->frame)); + fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER, FALSE, block->space, block->offset, 0, UNIV_PAGE_SIZE, (void*)block->frame, (void*)block); diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 09883fbb037..5e90f5952fc 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -342,6 +342,16 @@ buf_frame_get_modify_clock( /*=======================*/ /* out: value */ buf_frame_t* frame); /* in: pointer to a frame */ +/************************************************************************ +Calculates a page checksum which is stored to the page when it is written +to a file. Note that we must be careful to calculate the same value +on 32-bit and 64-bit architectures. */ + +ulint +buf_calc_page_checksum( +/*===================*/ + /* out: checksum */ + byte* page); /* in: buffer page */ /************************************************************************** Gets the page number of a pointer pointing within a buffer frame containing a file page. */ diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 894ef9c3840..e93cd3f0364 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -882,12 +882,6 @@ recv_recover_page( recv = UT_LIST_GET_NEXT(rec_list, recv); } - /* If the following assert fails, the file page is incompletely - written, and a recovery from a backup is required */ - - ut_a(0 == ut_dulint_cmp(mach_read_from_8(page + FIL_PAGE_LSN), - mach_read_from_8(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN))); mutex_enter(&(recv_sys->mutex)); recv_addr->state = RECV_PROCESSED; |