diff options
Diffstat (limited to 'storage/innobase/fil/fil0pagecompress.cc')
-rw-r--r-- | storage/innobase/fil/fil0pagecompress.cc | 272 |
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); } |