summaryrefslogtreecommitdiff
path: root/storage/innobase/fil/fil0pagecompress.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/fil/fil0pagecompress.cc')
-rw-r--r--storage/innobase/fil/fil0pagecompress.cc272
1 files changed, 142 insertions, 130 deletions
diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc
index edc932f36f5..1ff04919121 100644
--- a/storage/innobase/fil/fil0pagecompress.cc
+++ b/storage/innobase/fil/fil0pagecompress.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (C) 2013, 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (C) 2013, 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -26,15 +26,19 @@ Updated 14/02/2015
#include "fil0fil.h"
#include "fil0pagecompress.h"
+#include "mtr0types.h"
+#include "mach0data.h"
+#include "buf0buf.h"
+#include "buf0checksum.h"
+#include "fsp0pagecompress.h"
+#ifndef UNIV_INNOCHECKSUM
#include <debug_sync.h>
#include <my_dbug.h>
#include "mem0mem.h"
#include "hash0hash.h"
#include "os0file.h"
-#include "mach0data.h"
-#include "buf0buf.h"
#include "buf0flu.h"
#include "log0recv.h"
#include "fsp0fsp.h"
@@ -364,8 +368,6 @@ fil_compress_page(
/* Set up the page header */
memcpy(out_buf, buf, FIL_PAGE_DATA);
- /* Set up the checksum */
- mach_write_to_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM, BUF_NO_CHECKSUM_MAGIC);
/* Set up the compression algorithm */
mach_write_to_8(out_buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, comp_method);
@@ -382,10 +384,13 @@ fil_compress_page(
/* Set up the actual payload lenght */
mach_write_to_2(out_buf+FIL_PAGE_DATA, write_size);
+ /* Set up the checksum */
+ mach_write_to_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM, buf_calc_compressed_crc32(out_buf));
+
#ifdef UNIV_DEBUG
/* Verify */
ut_ad(fil_page_is_compressed(out_buf) || fil_page_is_compressed_encrypted(out_buf));
- ut_ad(mach_read_from_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM) == BUF_NO_CHECKSUM_MAGIC);
+ ut_ad(mach_read_from_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM) == buf_calc_compressed_crc32(out_buf));
ut_ad(mach_read_from_2(out_buf+FIL_PAGE_DATA) == write_size);
ut_ad(mach_read_from_8(out_buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) == (ulint)comp_method ||
mach_read_from_2(out_buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE) == (ulint)comp_method);
@@ -399,7 +404,7 @@ fil_compress_page(
uncomp_page = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE));
memcpy(comp_page, out_buf, UNIV_PAGE_SIZE);
- fil_decompress_page(uncomp_page, comp_page, ulong(len), NULL);
+ ut_ad(fil_decompress_page(uncomp_page, comp_page, ulong(len), NULL));
if (buf_page_is_corrupted(false, uncomp_page, 0, space)) {
buf_page_print(uncomp_page, 0);
@@ -466,22 +471,25 @@ err_exit:
}
-/****************************************************************//**
+/**
For page compressed pages decompress the page after actual read
-operation. */
+operation.
+@param[in,out] page_buf Preallocated temporal buffer where
+ compression is done and then copied
+ to the buffer.
+@param[in,out] buf Compressed page and after suggesful
+ decompression operation uncompressed page
+ is copied here.
+@param[in] len Length of output buffer.
+@param[out] write_size Actual payload size of the compressed data.
+@return true when operation succeeded or false when failed */
UNIV_INTERN
-void
+bool
fil_decompress_page(
-/*================*/
- byte* page_buf, /*!< in: preallocated buffer or NULL */
- byte* buf, /*!< out: buffer from which to read; in aio
- this must be appropriately aligned */
- ulong len, /*!< in: length of output buffer.*/
- ulint* write_size, /*!< in/out: Actual payload size of
- the compressed data. */
- bool return_error) /*!< in: true if only an error should
- be produced when decompression fails.
- By default this parameter is false. */
+ byte* page_buf,
+ byte* buf,
+ ulong len,
+ ulint* write_size)
{
int err = 0;
ulint actual_size = 0;
@@ -503,7 +511,7 @@ fil_decompress_page(
if (ptype != FIL_PAGE_PAGE_COMPRESSED &&
ptype != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED &&
ptype != FIL_PAGE_TYPE_COMPRESSED) {
- return;
+ ut_error;
}
// If no buffer was given, we need to allocate temporal buffer
@@ -514,24 +522,6 @@ fil_decompress_page(
in_buf = page_buf;
}
- /* Before actual decompress, make sure that page type is correct */
-
- if (mach_read_from_4(buf+FIL_PAGE_SPACE_OR_CHKSUM) != BUF_NO_CHECKSUM_MAGIC ||
- (ptype != FIL_PAGE_PAGE_COMPRESSED &&
- ptype != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED)) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: We try to uncompress corrupted page"
- " CRC " ULINTPF " type " ULINTPF " len " ULINTPF ".",
- mach_read_from_4(buf+FIL_PAGE_SPACE_OR_CHKSUM),
- mach_read_from_2(buf+FIL_PAGE_TYPE), len);
-
- fflush(stderr);
- if (return_error) {
- goto error_return;
- }
- ut_error;
- }
-
/* Get compression algorithm */
if (ptype == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
compression_alg = mach_read_from_2(buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE);
@@ -541,17 +531,10 @@ fil_decompress_page(
/* Get the actual size of compressed page */
actual_size = mach_read_from_2(buf+FIL_PAGE_DATA);
+
/* Check if payload size is corrupted */
if (actual_size == 0 || actual_size > UNIV_PAGE_SIZE) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: We try to uncompress corrupted page"
- " actual size " ULINTPF " compression %s.",
- actual_size, fil_get_compression_alg_name(compression_alg));
- fflush(stderr);
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ goto error_return;
}
/* Store actual payload size of the compressed data. This pointer
@@ -570,19 +553,7 @@ fil_decompress_page(
/* If uncompress fails it means that page is corrupted */
if (err != Z_OK) {
-
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but uncompress failed with error %d "
- " size " ULINTPF " len " ULINTPF ".",
- err, actual_size, len);
-
- fflush(stderr);
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ goto error_return;
}
break;
@@ -591,18 +562,7 @@ fil_decompress_page(
err = LZ4_decompress_fast((const char *)buf+header_len, (char *)in_buf, len);
if (err != (int)actual_size) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but uncompress failed with error %d "
- " size " ULINTPF " len " ULINTPF ".",
- err, actual_size, len);
-
- fflush(stderr);
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ goto error_return;
}
break;
#endif /* HAVE_LZ4 */
@@ -616,18 +576,7 @@ fil_decompress_page(
olen = olen_lzo;
if (err != LZO_E_OK || (olen == 0 || olen > UNIV_PAGE_SIZE)) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but uncompress failed with error %d "
- " size " ULINTPF " len " ULINTPF ".",
- err, actual_size, len);
-
- fflush(stderr);
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ goto error_return;
}
break;
}
@@ -653,17 +602,7 @@ fil_decompress_page(
if (ret != LZMA_OK || (dst_pos == 0 || dst_pos > UNIV_PAGE_SIZE)) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but decompression read only %ld bytes"
- " size " ULINTPF "len " ULINTPF ".",
- dst_pos, actual_size, len);
- fflush(stderr);
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ goto error_return;
}
break;
@@ -682,17 +621,8 @@ fil_decompress_page(
0);
if (err != BZ_OK || (dst_pos == 0 || dst_pos > UNIV_PAGE_SIZE)) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but decompression read only %du bytes"
- " size " ULINTPF " len " ULINTPF " err %d.",
- dst_pos, actual_size, len, err);
- fflush(stderr);
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ len = dst_pos;
+ goto error_return;
}
break;
}
@@ -709,35 +639,17 @@ fil_decompress_page(
(char *)in_buf,
(size_t*)&olen);
- if (cstatus != SNAPPY_OK || olen != UNIV_PAGE_SIZE) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but decompression read only " ULINTPF " bytes"
- " size " ULINTPF " len " ULINTPF " err %d.",
- olen, actual_size, len, (int)cstatus);
- fflush(stderr);
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ if (cstatus != SNAPPY_OK || (olen == 0 || olen > UNIV_PAGE_SIZE)) {
+ err = (int)cstatus;
+ len = olen;
+ goto error_return;
}
break;
}
#endif /* HAVE_SNAPPY */
default:
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Corruption: Page is marked as compressed"
- " but compression algorithm %s"
- " is not known."
- ,fil_get_compression_alg_name(compression_alg));
-
- fflush(stderr);
- if (return_error) {
- goto error_return;
- }
- ut_error;
+ goto error_return;
break;
}
@@ -747,8 +659,108 @@ fil_decompress_page(
really any other options. */
memcpy(buf, in_buf, len);
+ if (page_buf != in_buf) {
+ ut_free(in_buf);
+ }
+ return true;
+
error_return:
if (page_buf != in_buf) {
ut_free(in_buf);
}
+
+ /* Note that as we have found the page is corrupted, so
+ all this could be incorrect. */
+ ulint space_id = mach_read_from_4(buf+FIL_PAGE_SPACE_ID);
+ fil_space_t* space = fil_space_acquire_for_io(space_id);
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Corruption: Page is marked as compressed"
+ " space : " ULINTPF " name %s "
+ " but uncompress failed with error: %d"
+ " size: " ULINTPF
+ " len: " ULINTPF
+ " compression method %s",
+ space_id,
+ (space ? space->chain.start->name : "(import)"),
+ err,
+ actual_size,
+ len,
+ fil_get_compression_alg_name(compression_alg));
+
+ if (space) {
+ fil_space_release(space);
+ }
+
+ return false;
+}
+#endif /* !UNIV_INNOCHECKSUM */
+
+/**
+Verify that stored post compression checksum matches calculated
+checksum. Note that old format did not have a checksum and
+in that case either original pre-compression page checksum will
+fail after decompression or page decompression fails.
+
+@param[in,out] page page frame
+@param[in] space_id Tablespace identifier
+@param[in] offset Page offset
+@return true if post compression checksum matches, false otherwise */
+#ifndef UNIV_INNOCHECKSUM
+UNIV_INTERN
+#endif
+bool
+fil_verify_compression_checksum(
+ const byte* page,
+ ulint space_id,
+ ulint offset)
+{
+ ut_ad(page &&
+ (mach_read_from_2(page+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED
+ || mach_read_from_2(page+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED));
+
+ uint32_t checksum = mach_read_from_4(page+FIL_PAGE_SPACE_OR_CHKSUM);
+
+ /* In earlier versions supporting page compression, page compression
+ stored BUF_NO_CHECKSUM_MAGIC to checksum filed. These pages are
+ treaded as not corrupted. */
+ if (checksum == BUF_NO_CHECKSUM_MAGIC) {
+ return (true);
+ }
+
+ uint32_t cchecksum = buf_calc_compressed_crc32(page);
+
+ if (checksum != cchecksum) {
+ ulint comp_method = mach_read_from_2(page+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED
+ ? mach_read_from_8(page+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)
+ : mach_read_from_2(page+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE);
+
+#ifdef UNIV_INNOCHECKSUM
+ fprintf(log_file ? log_file : stderr,
+ "Page " ULINTPF ":" ULINTPF " may be corrupted."
+ " Post compression checksum %u"
+ " stored %u compression_method %s\n",
+ space_id, offset, checksum, cchecksum,
+ fil_get_compression_alg_name(comp_method));
+#else /*! UNIV_INNOCHECKSUM */
+ FilSpace space(space_id, true);
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page [page id: space=" ULINTPF
+ ", page number= " ULINTPF "]"
+ " in file %s"
+ " may be corrupted."
+ " Post compression checksum %u"
+ " stored %u"
+ " compression_method %s",
+ space_id,
+ offset,
+ (space() ? space()->chain.start->name : "(import)"),
+ checksum,
+ cchecksum,
+ fil_get_compression_alg_name(comp_method));
+#endif
+ }
+
+ return (checksum == cchecksum);
}