summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--innobase/buf/buf0buf.c56
-rw-r--r--innobase/buf/buf0flu.c6
-rw-r--r--innobase/include/buf0buf.h10
-rw-r--r--innobase/log/log0recv.c6
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;