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.cc580
1 files changed, 168 insertions, 412 deletions
diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc
index 507f452aa20..ca5fc036c45 100644
--- a/storage/innobase/fil/fil0pagecompress.cc
+++ b/storage/innobase/fil/fil0pagecompress.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (C) 2013, 2017, MariaDB Corporation.
+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
@@ -74,73 +74,26 @@ Updated 14/02/2015
#include "snappy-c.h"
#endif
-/* Used for debugging */
-//#define UNIV_PAGECOMPRESS_DEBUG 1
-
-/****************************************************************//**
-For page compressed pages compress the page before actual write
-operation.
-@return compressed page to be written*/
-UNIV_INTERN
-byte*
-fil_compress_page(
-/*==============*/
- fil_space_t* space, /*!< in,out: tablespace (NULL during IMPORT) */
- byte* buf, /*!< in: buffer from which to write; in aio
- this must be appropriately aligned */
- byte* out_buf, /*!< out: compressed buffer */
- ulint len, /*!< in: length of input buffer.*/
- ulint level, /* in: compression level */
- ulint block_size, /*!< in: block size */
- bool encrypted, /*!< in: is page also encrypted */
- ulint* out_len) /*!< out: actual length of compressed
- page */
+/** Compress a page_compressed page before writing to a data file.
+@param[in] buf page to be compressed
+@param[out] out_buf compressed page
+@param[in] level compression level
+@param[in] block_size file system block size
+@param[in] encrypted whether the page will be subsequently encrypted
+@return actual length of compressed page
+@retval 0 if the page was not compressed */
+ulint fil_page_compress(const byte* buf, byte* out_buf, ulint level,
+ ulint block_size, bool encrypted)
{
- int err = Z_OK;
int comp_level = int(level);
ulint header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
- ulint write_size = 0;
-#if defined(HAVE_LZO)
- lzo_uint write_size_lzo = write_size;
-#endif
/* Cache to avoid change during function execution */
ulint comp_method = innodb_compression_algorithm;
- bool allocated = false;
-
- /* page_compression does not apply to tables or tablespaces
- that use ROW_FORMAT=COMPRESSED */
- ut_ad(!space || !FSP_FLAGS_GET_ZIP_SSIZE(space->flags));
if (encrypted) {
header_len += FIL_PAGE_COMPRESSION_METHOD_SIZE;
}
- if (!out_buf) {
- allocated = true;
- ulint size = srv_page_size;
-
- /* Both snappy and lzo compression methods require that
- output buffer used for compression is bigger than input
- buffer. Increase the allocated buffer size accordingly. */
-#if defined(HAVE_SNAPPY)
- if (comp_method == PAGE_SNAPPY_ALGORITHM) {
- size = snappy_max_compressed_length(size);
- }
-#endif
-#if defined(HAVE_LZO)
- if (comp_method == PAGE_LZO_ALGORITHM) {
- size += LZO1X_1_15_MEM_COMPRESS;
- }
-#endif
-
- out_buf = static_cast<byte *>(ut_malloc_nokey(size));
- }
-
- ut_ad(buf);
- ut_ad(out_buf);
- ut_ad(len);
- ut_ad(out_len);
-
/* Let's not compress file space header or
extent descriptor */
switch (fil_page_get_type(buf)) {
@@ -148,8 +101,7 @@ fil_compress_page(
case FIL_PAGE_TYPE_FSP_HDR:
case FIL_PAGE_TYPE_XDES:
case FIL_PAGE_PAGE_COMPRESSED:
- *out_len = len;
- goto err_exit;
+ return 0;
}
/* If no compression level was provided to this table, use system
@@ -158,125 +110,113 @@ fil_compress_page(
comp_level = int(page_zip_level);
}
- DBUG_LOG("compress", "Preparing for space "
- << (space ? space->id : 0) << " '"
- << (space ? space->name : "(import)") << "' len " << len);
-
- write_size = srv_page_size - header_len;
+ ulint write_size = srv_page_size - header_len;
- switch(comp_method) {
+ switch (comp_method) {
+ default:
+ ut_ad(!"unknown compression method");
+ /* fall through */
+ case PAGE_UNCOMPRESSED:
+ return 0;
+ case PAGE_ZLIB_ALGORITHM:
+ {
+ ulong len = uLong(write_size);
+ if (Z_OK == compress2(
+ out_buf + header_len, &len,
+ buf, uLong(srv_page_size), comp_level)) {
+ write_size = len;
+ goto success;
+ }
+ }
+ break;
#ifdef HAVE_LZ4
case PAGE_LZ4_ALGORITHM:
-
-#ifdef HAVE_LZ4_COMPRESS_DEFAULT
- err = LZ4_compress_default((const char *)buf,
- (char *)out_buf+header_len, len, write_size);
-#else
- err = LZ4_compress_limitedOutput((const char *)buf,
- (char *)out_buf+header_len, len, write_size);
-#endif /* HAVE_LZ4_COMPRESS_DEFAULT */
- write_size = err;
-
- if (err == 0) {
- goto err_exit;
+# ifdef HAVE_LZ4_COMPRESS_DEFAULT
+ write_size = LZ4_compress_default(
+ reinterpret_cast<const char*>(buf),
+ reinterpret_cast<char*>(out_buf) + header_len,
+ int(srv_page_size), int(write_size));
+# else
+ write_size = LZ4_compress_limitedOutput(
+ reinterpret_cast<const char*>(buf),
+ reinterpret_cast<char*>(out_buf) + header_len,
+ int(srv_page_size), int(write_size));
+# endif
+
+ if (write_size) {
+ goto success;
}
break;
#endif /* HAVE_LZ4 */
#ifdef HAVE_LZO
- case PAGE_LZO_ALGORITHM:
- err = lzo1x_1_15_compress(
- buf, len, out_buf+header_len, &write_size_lzo, out_buf+srv_page_size);
-
- write_size = write_size_lzo;
-
- if (err != LZO_E_OK || write_size > srv_page_size-header_len) {
- goto err_exit;
+ case PAGE_LZO_ALGORITHM: {
+ lzo_uint len = write_size;
+
+ if (LZO_E_OK == lzo1x_1_15_compress(
+ buf, srv_page_size,
+ out_buf + header_len, &len,
+ out_buf + srv_page_size)
+ && len <= write_size) {
+ write_size = len;
+ goto success;
}
-
break;
+ }
#endif /* HAVE_LZO */
#ifdef HAVE_LZMA
case PAGE_LZMA_ALGORITHM: {
- size_t out_pos=0;
-
- err = lzma_easy_buffer_encode(
- comp_level,
- LZMA_CHECK_NONE,
- NULL, /* No custom allocator, use malloc/free */
- reinterpret_cast<uint8_t*>(buf),
- len,
- reinterpret_cast<uint8_t*>(out_buf + header_len),
- &out_pos,
- (size_t)write_size);
-
- if (err != LZMA_OK || out_pos > srv_page_size-header_len) {
+ size_t out_pos = 0;
+
+ if (LZMA_OK == lzma_easy_buffer_encode(
+ comp_level, LZMA_CHECK_NONE, NULL,
+ buf, srv_page_size, out_buf + header_len,
+ &out_pos, write_size)
+ && out_pos <= write_size) {
write_size = out_pos;
- goto err_exit;
+ goto success;
}
-
- write_size = out_pos;
-
break;
}
#endif /* HAVE_LZMA */
#ifdef HAVE_BZIP2
case PAGE_BZIP2_ALGORITHM: {
-
- err = BZ2_bzBuffToBuffCompress(
- (char *)(out_buf + header_len),
- (unsigned int *)&write_size,
- (char *)buf,
- len,
- 1,
- 0,
- 0);
-
- if (err != BZ_OK || write_size > srv_page_size-header_len) {
- goto err_exit;
+ unsigned len = unsigned(write_size);
+ if (BZ_OK == BZ2_bzBuffToBuffCompress(
+ reinterpret_cast<char*>(out_buf + header_len),
+ &len,
+ const_cast<char*>(
+ reinterpret_cast<const char*>(buf)),
+ unsigned(srv_page_size), 1, 0, 0)
+ && len <= write_size) {
+ write_size = len;
+ goto success;
}
break;
}
#endif /* HAVE_BZIP2 */
#ifdef HAVE_SNAPPY
- case PAGE_SNAPPY_ALGORITHM:
- {
- snappy_status cstatus;
- write_size = snappy_max_compressed_length(srv_page_size);
-
- cstatus = snappy_compress(
- (const char *)buf,
- (size_t)len,
- (char *)(out_buf+header_len),
- (size_t*)&write_size);
-
- if (cstatus != SNAPPY_OK || write_size > srv_page_size-header_len) {
- err = (int)cstatus;
- goto err_exit;
+ case PAGE_SNAPPY_ALGORITHM: {
+ size_t len = snappy_max_compressed_length(srv_page_size);
+
+ if (SNAPPY_OK == snappy_compress(
+ reinterpret_cast<const char*>(buf),
+ srv_page_size,
+ reinterpret_cast<char*>(out_buf) + header_len,
+ &len)
+ && len <= write_size) {
+ write_size = len;
+ goto success;
}
break;
}
#endif /* HAVE_SNAPPY */
-
- case PAGE_ZLIB_ALGORITHM:
- err = compress2(out_buf+header_len, (ulong*)&write_size, buf,
- uLong(len), comp_level);
-
- if (err != Z_OK) {
- goto err_exit;
- }
- break;
-
- case PAGE_UNCOMPRESSED:
- *out_len = len;
- return (buf);
- break;
- default:
- ut_error;
- break;
}
+ srv_stats.pages_page_compression_error.inc();
+ return 0;
+success:
/* Set up the page header */
memcpy(out_buf, buf, FIL_PAGE_DATA);
/* Set up the checksum */
@@ -307,23 +247,12 @@ fil_compress_page(
/* Verify that page can be decompressed */
{
- byte *comp_page;
- byte *uncomp_page;
-
- comp_page = static_cast<byte *>(ut_malloc_nokey(srv_page_size));
- uncomp_page = static_cast<byte *>(ut_malloc_nokey(srv_page_size));
- memcpy(comp_page, out_buf, srv_page_size);
-
- fil_decompress_page(uncomp_page, comp_page, ulong(len), NULL);
-
- if (buf_page_is_corrupted(false, uncomp_page, univ_page_size,
- space)) {
- buf_page_print(uncomp_page, univ_page_size);
- ut_ad(0);
- }
-
- ut_free(comp_page);
- ut_free(uncomp_page);
+ page_t tmp_buf[UNIV_PAGE_SIZE_MAX];
+ page_t page[UNIV_PAGE_SIZE_MAX];
+ memcpy(page, out_buf, srv_page_size);
+ ut_ad(fil_page_decompress(tmp_buf, page));
+ ut_ad(!buf_page_is_corrupted(false, page, univ_page_size,
+ NULL));
}
#endif /* UNIV_DEBUG */
@@ -347,310 +276,137 @@ fil_compress_page(
#endif
}
- DBUG_LOG("compress", "Succeeded for space "
- << (space ? space->id : 0) << " '"
- << (space ? space->name : "(import)")
- << "' len " << len << " out_len " << write_size);
-
- srv_stats.page_compression_saved.add((len - write_size));
+ srv_stats.page_compression_saved.add(srv_page_size - write_size);
srv_stats.pages_page_compressed.inc();
- *out_len = write_size;
-
- if (allocated) {
- /* TODO: reduce number of memcpy's */
- memcpy(buf, out_buf, len);
- goto exit_free;
- } else {
- return(out_buf);
- }
-
-err_exit:
- /* If error we leave the actual page as it was */
-
-#ifndef UNIV_PAGECOMPRESS_DEBUG
- if (space && !space->printed_compression_failure) {
- space->printed_compression_failure = true;
-#endif
- ib::warn() << "Compression failed for space: "
- << space->id << " name: "
- << space->name << " len: "
- << len << " err: " << err << " write_size: "
- << write_size
- << " compression method: "
- << fil_get_compression_alg_name(comp_method)
- << ".";
-#ifndef UNIV_PAGECOMPRESS_DEBUG
- }
-#endif
- srv_stats.pages_page_compression_error.inc();
- *out_len = len;
-
-exit_free:
- if (allocated) {
- ut_free(out_buf);
- }
-
- return (buf);
-
+ return write_size;
}
-/****************************************************************//**
-For page compressed pages decompress the page after actual read
-operation. */
-UNIV_INTERN
-void
-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. */
+/** Decompress a page that may be subject to page_compressed compression.
+@param[in,out] tmp_buf temporary buffer (of innodb_page_size)
+@param[in,out] buf possibly compressed page buffer
+@return size of the compressed data
+@retval 0 if decompression failed
+@retval srv_page_size if the page was not compressed */
+ulint fil_page_decompress(byte* tmp_buf, byte* buf)
{
- int err = 0;
- ulint actual_size = 0;
- ib_uint64_t compression_alg = 0;
- byte *in_buf;
- ulint ptype;
+ const unsigned ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
ulint header_len;
-
- ut_ad(buf);
- ut_ad(len);
-
- ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
-
+ uint64_t compression_alg;
switch (ptype) {
case FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED:
header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE
+ FIL_PAGE_COMPRESSION_METHOD_SIZE;
+ compression_alg = mach_read_from_2(
+ FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE + buf);
break;
case FIL_PAGE_PAGE_COMPRESSED:
header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
+ compression_alg = mach_read_from_8(
+ FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + buf);
break;
default:
- /* The page is not in our format. */
- return;
+ return srv_page_size;
}
- // If no buffer was given, we need to allocate temporal buffer
- if (page_buf == NULL) {
- in_buf = static_cast<byte *>(ut_malloc_nokey(srv_page_size));
- memset(in_buf, 0, srv_page_size);
- } else {
- in_buf = page_buf;
+ if (mach_read_from_4(buf + FIL_PAGE_SPACE_OR_CHKSUM)
+ != BUF_NO_CHECKSUM_MAGIC) {
+ return 0;
}
- /* Before actual decompress, make sure that page type is correct */
+ ulint actual_size = mach_read_from_2(buf + FIL_PAGE_DATA);
- 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::error() << "Corruption: We try to uncompress corrupted "
- "page CRC "
- << mach_read_from_4(buf+FIL_PAGE_SPACE_OR_CHKSUM)
- << " type " << ptype << " len " << len << ".";
-
- if (return_error) {
- goto error_return;
- }
- ut_error;
- }
-
- /* Get compression algorithm */
- if (ptype == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
- compression_alg = static_cast<ib_uint64_t>(mach_read_from_2(buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE));
- } else {
- compression_alg = mach_read_from_8(buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
- }
-
- /* 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 > srv_page_size) {
- ib::error() << "Corruption: We try to uncompress corrupted page"
- << " actual size: " << actual_size
- << " compression method: "
- << fil_get_compression_alg_name(compression_alg)
- << ".";
- if (return_error) {
- goto error_return;
- }
- ut_error;
- }
-
- /* Store actual payload size of the compressed data. This pointer
- points to buffer pool. */
- if (write_size) {
- *write_size = actual_size;
+ if (actual_size == 0 || actual_size > srv_page_size - header_len) {
+ return 0;
}
- DBUG_LOG("compress", "Preparing for decompress for len "
- << actual_size << ".");
-
- switch(compression_alg) {
+ switch (compression_alg) {
+ default:
+ ib::error() << "Unknown compression algorithm "
+ << compression_alg;
+ return 0;
case PAGE_ZLIB_ALGORITHM:
- err= uncompress(in_buf, &len, buf+header_len, (unsigned long)actual_size);
-
- /* If uncompress fails it means that page is corrupted */
- if (err != Z_OK) {
- goto err_exit;
- if (return_error) {
- goto error_return;
+ {
+ uLong len = srv_page_size;
+ if (Z_OK != uncompress(tmp_buf, &len,
+ buf + header_len,
+ uLong(actual_size))
+ && len != srv_page_size) {
+ return 0;
}
}
break;
-
#ifdef HAVE_LZ4
case PAGE_LZ4_ALGORITHM:
- err = LZ4_decompress_fast((const char *)buf+header_len, (char *)in_buf, len);
-
- if (err != (int)actual_size) {
- goto err_exit;
- if (return_error) {
- goto error_return;
- }
+ if (LZ4_decompress_safe(reinterpret_cast<const char*>(buf)
+ + header_len,
+ reinterpret_cast<char*>(tmp_buf),
+ actual_size, srv_page_size)
+ == int(srv_page_size)) {
+ break;
}
- break;
+ return 0;
#endif /* HAVE_LZ4 */
#ifdef HAVE_LZO
case PAGE_LZO_ALGORITHM: {
- ulint olen = 0;
- lzo_uint olen_lzo = olen;
- err = lzo1x_decompress((const unsigned char *)buf+header_len,
- actual_size,(unsigned char *)in_buf, &olen_lzo, NULL);
-
- olen = olen_lzo;
-
- if (err != LZO_E_OK || (olen == 0 || olen > srv_page_size)) {
- len = olen;
- goto err_exit;
- if (return_error) {
- goto error_return;
- }
+ lzo_uint len_lzo = srv_page_size;
+ if (LZO_E_OK == lzo1x_decompress_safe(
+ buf + header_len,
+ actual_size, tmp_buf, &len_lzo, NULL)
+ && len_lzo == srv_page_size) {
+ break;
}
- break;
+ return 0;
}
#endif /* HAVE_LZO */
#ifdef HAVE_LZMA
case PAGE_LZMA_ALGORITHM: {
-
- lzma_ret ret;
size_t src_pos = 0;
size_t dst_pos = 0;
uint64_t memlimit = UINT64_MAX;
- ret = lzma_stream_buffer_decode(
- &memlimit,
- 0,
- NULL,
- buf+header_len,
- &src_pos,
- actual_size,
- in_buf,
- &dst_pos,
- len);
-
-
- if (ret != LZMA_OK || (dst_pos == 0 || dst_pos > srv_page_size)) {
- len = dst_pos;
- goto err_exit;
- if (return_error) {
- goto error_return;
- }
+ if (LZMA_OK == lzma_stream_buffer_decode(
+ &memlimit, 0, NULL, buf + header_len,
+ &src_pos, actual_size, tmp_buf, &dst_pos,
+ srv_page_size)
+ && dst_pos == srv_page_size) {
+ break;
}
-
- break;
+ return 0;
}
#endif /* HAVE_LZMA */
#ifdef HAVE_BZIP2
case PAGE_BZIP2_ALGORITHM: {
unsigned int dst_pos = srv_page_size;
-
- err = BZ2_bzBuffToBuffDecompress(
- (char *)in_buf,
- &dst_pos,
- (char *)(buf+header_len),
- actual_size,
- 1,
- 0);
-
- if (err != BZ_OK || (dst_pos == 0 || dst_pos > srv_page_size)) {
- len = dst_pos;
- goto err_exit;
- if (return_error) {
- goto error_return;
- }
+ if (BZ_OK == BZ2_bzBuffToBuffDecompress(
+ reinterpret_cast<char*>(tmp_buf),
+ &dst_pos,
+ reinterpret_cast<char*>(buf) + header_len,
+ actual_size, 1, 0)
+ && dst_pos == srv_page_size) {
+ break;
}
- break;
+ return 0;
}
#endif /* HAVE_BZIP2 */
#ifdef HAVE_SNAPPY
- case PAGE_SNAPPY_ALGORITHM:
- {
- snappy_status cstatus;
- ulint olen = srv_page_size;
-
- cstatus = snappy_uncompress(
- (const char *)(buf+header_len),
- (size_t)actual_size,
- (char *)in_buf,
- (size_t*)&olen);
-
- if (cstatus != SNAPPY_OK || (olen == 0 || olen > srv_page_size)) {
- err = (int)cstatus;
- len = olen;
- goto err_exit;
- if (return_error) {
- goto error_return;
- }
+ case PAGE_SNAPPY_ALGORITHM: {
+ size_t olen = srv_page_size;
+
+ if (SNAPPY_OK == snappy_uncompress(
+ reinterpret_cast<const char*>(buf) + header_len,
+ actual_size,
+ reinterpret_cast<char*>(tmp_buf), &olen)
+ && olen == srv_page_size) {
+ break;
}
-
- break;
+ return 0;
}
#endif /* HAVE_SNAPPY */
- default:
- goto err_exit;
- if (return_error) {
- goto error_return;
- }
- break;
}
srv_stats.pages_page_decompressed.inc();
-
- /* Copy the uncompressed page to the buffer pool, not
- really any other options. */
- memcpy(buf, in_buf, len);
-
-error_return:
- if (page_buf != in_buf) {
- ut_free(in_buf);
- }
-
- return;
-
-err_exit:
- /* 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::error() << "Corruption: Page is marked as compressed"
- << " space: " << space_id << " name: "
- << (space ? space->name : "NULL")
- << " but uncompress failed with error: " << err
- << " size: " << actual_size
- << " len: " << len
- << " compression method: "
- << fil_get_compression_alg_name(compression_alg) << ".";
-
- buf_page_print(buf, univ_page_size);
- space->release_for_io();
- ut_ad(0);
+ memcpy(buf, tmp_buf, srv_page_size);
+ return actual_size;
}