2013-12-19 14:36:38 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
|
2017-03-30 12:48:42 +02:00
|
|
|
Copyright (C) 2013, 2017, MariaDB Corporation.
|
2013-12-19 14:36:38 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/******************************************************************//**
|
|
|
|
@file fil/fil0pagecompress.cc
|
|
|
|
Implementation for page compressed file spaces.
|
|
|
|
|
2015-02-19 17:42:18 +02:00
|
|
|
Created 11/12/2013 Jan Lindström jan.lindstrom@mariadb.com
|
|
|
|
Updated 14/02/2015
|
2013-12-19 14:36:38 +02:00
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
#include "fil0fil.h"
|
|
|
|
#include "fil0pagecompress.h"
|
|
|
|
|
|
|
|
#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"
|
|
|
|
#include "srv0srv.h"
|
|
|
|
#include "srv0start.h"
|
|
|
|
#include "mtr0mtr.h"
|
|
|
|
#include "mtr0log.h"
|
|
|
|
#include "dict0dict.h"
|
|
|
|
#include "page0page.h"
|
|
|
|
#include "page0zip.h"
|
|
|
|
#include "trx0sys.h"
|
|
|
|
#include "row0mysql.h"
|
2015-03-02 10:55:48 +02:00
|
|
|
#include "ha_prototypes.h" // IB_LOG_
|
2016-12-30 15:04:10 +02:00
|
|
|
#include "buf0lru.h"
|
|
|
|
#include "ibuf0ibuf.h"
|
|
|
|
#include "sync0sync.h"
|
2013-12-19 14:36:38 +02:00
|
|
|
#include "zlib.h"
|
|
|
|
#ifdef __linux__
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
#include "row0mysql.h"
|
2014-02-11 20:05:09 +02:00
|
|
|
#ifdef HAVE_LZ4
|
2014-02-03 10:08:15 +02:00
|
|
|
#include "lz4.h"
|
2014-02-11 20:05:09 +02:00
|
|
|
#endif
|
2014-04-15 14:28:25 +03:00
|
|
|
#ifdef HAVE_LZO
|
|
|
|
#include "lzo/lzo1x.h"
|
|
|
|
#endif
|
2014-07-21 22:21:30 +03:00
|
|
|
#ifdef HAVE_LZMA
|
|
|
|
#include "lzma.h"
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_BZIP2
|
|
|
|
#include "bzlib.h"
|
|
|
|
#endif
|
2015-02-19 17:42:18 +02:00
|
|
|
#ifdef HAVE_SNAPPY
|
|
|
|
#include "snappy-c.h"
|
|
|
|
#endif
|
2014-04-15 14:28:25 +03:00
|
|
|
|
2014-04-23 19:23:11 +03:00
|
|
|
/* Used for debugging */
|
|
|
|
//#define UNIV_PAGECOMPRESS_DEBUG 1
|
2013-12-19 14:36:38 +02:00
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
For page compressed pages compress the page before actual write
|
|
|
|
operation.
|
|
|
|
@return compressed page to be written*/
|
2015-06-03 13:10:18 +03:00
|
|
|
UNIV_INTERN
|
2013-12-19 14:36:38 +02:00
|
|
|
byte*
|
|
|
|
fil_compress_page(
|
|
|
|
/*==============*/
|
2017-04-21 11:28:18 +03:00
|
|
|
fil_space_t* space, /*!< in,out: tablespace (NULL during IMPORT) */
|
2015-06-03 13:10:18 +03:00
|
|
|
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 */
|
2017-05-20 21:49:35 +03:00
|
|
|
ulint* out_len) /*!< out: actual length of compressed
|
2015-06-03 13:10:18 +03:00
|
|
|
page */
|
2013-12-19 14:36:38 +02:00
|
|
|
{
|
2015-06-03 13:10:18 +03:00
|
|
|
int err = Z_OK;
|
2017-03-01 08:27:39 +02:00
|
|
|
int comp_level = int(level);
|
2015-06-03 13:10:18 +03:00
|
|
|
ulint header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
|
2017-05-20 21:49:35 +03:00
|
|
|
ulint write_size = 0;
|
2014-12-22 16:53:17 +02:00
|
|
|
/* Cache to avoid change during function execution */
|
|
|
|
ulint comp_method = innodb_compression_algorithm;
|
2017-05-20 21:49:35 +03:00
|
|
|
bool allocated = false;
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2017-04-21 11:28:18 +03:00
|
|
|
/* page_compression does not apply to tables or tablespaces
|
|
|
|
that use ROW_FORMAT=COMPRESSED */
|
2017-04-21 17:32:02 +03:00
|
|
|
ut_ad(!space || !FSP_FLAGS_GET_ZIP_SSIZE(space->flags));
|
2017-04-21 11:28:18 +03:00
|
|
|
|
2015-06-03 13:10:18 +03:00
|
|
|
if (encrypted) {
|
|
|
|
header_len += FIL_PAGE_COMPRESSION_METHOD_SIZE;
|
|
|
|
}
|
|
|
|
|
2015-09-21 11:24:08 +03:00
|
|
|
if (!out_buf) {
|
|
|
|
allocated = true;
|
2017-05-20 21:49:35 +03:00
|
|
|
ulint size = UNIV_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 HAVE_SNAPPY
|
|
|
|
if (comp_method == PAGE_SNAPPY_ALGORITHM) {
|
|
|
|
size = snappy_max_compressed_length(size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if HAVE_LZO
|
2015-09-21 11:24:08 +03:00
|
|
|
if (comp_method == PAGE_LZO_ALGORITHM) {
|
2017-05-20 21:49:35 +03:00
|
|
|
size += LZO1X_1_15_MEM_COMPRESS;
|
2015-09-21 11:24:08 +03:00
|
|
|
}
|
|
|
|
#endif
|
2017-05-20 21:49:35 +03:00
|
|
|
|
2017-05-23 11:09:47 +03:00
|
|
|
out_buf = static_cast<byte *>(ut_malloc_nokey(size));
|
2015-09-21 11:24:08 +03:00
|
|
|
}
|
|
|
|
|
2014-01-13 15:02:31 +02:00
|
|
|
ut_ad(buf);
|
|
|
|
ut_ad(out_buf);
|
|
|
|
ut_ad(len);
|
|
|
|
ut_ad(out_len);
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-12-22 16:53:17 +02:00
|
|
|
/* Let's not compress file space header or
|
|
|
|
extent descriptor */
|
2017-04-21 11:28:18 +03:00
|
|
|
switch (fil_page_get_type(buf)) {
|
|
|
|
case 0:
|
|
|
|
case FIL_PAGE_TYPE_FSP_HDR:
|
|
|
|
case FIL_PAGE_TYPE_XDES:
|
|
|
|
case FIL_PAGE_PAGE_COMPRESSED:
|
2014-12-22 16:53:17 +02:00
|
|
|
*out_len = len;
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
|
|
|
|
/* If no compression level was provided to this table, use system
|
|
|
|
default level */
|
2015-06-03 13:10:18 +03:00
|
|
|
if (comp_level == 0) {
|
|
|
|
comp_level = page_zip_level;
|
2013-12-19 14:36:38 +02:00
|
|
|
}
|
|
|
|
|
2017-04-21 11:28:18 +03:00
|
|
|
DBUG_LOG("compress", "Preparing for space "
|
|
|
|
<< (space ? space->id : 0) << " '"
|
|
|
|
<< (space ? space->name : "(import)") << "' len " << len);
|
2013-12-19 14:36:38 +02:00
|
|
|
|
|
|
|
write_size = UNIV_PAGE_SIZE - header_len;
|
|
|
|
|
2014-07-31 11:31:39 +03:00
|
|
|
switch(comp_method) {
|
2014-02-11 20:05:09 +02:00
|
|
|
#ifdef HAVE_LZ4
|
2014-04-15 14:28:25 +03:00
|
|
|
case PAGE_LZ4_ALGORITHM:
|
2017-05-20 21:49:35 +03:00
|
|
|
|
2017-01-25 10:11:37 +02:00
|
|
|
#ifdef HAVE_LZ4_COMPRESS_DEFAULT
|
|
|
|
err = LZ4_compress_default((const char *)buf,
|
|
|
|
(char *)out_buf+header_len, len, write_size);
|
|
|
|
#else
|
2014-04-15 14:28:25 +03:00
|
|
|
err = LZ4_compress_limitedOutput((const char *)buf,
|
|
|
|
(char *)out_buf+header_len, len, write_size);
|
2017-01-25 10:11:37 +02:00
|
|
|
#endif /* HAVE_LZ4_COMPRESS_DEFAULT */
|
2014-02-03 10:08:15 +02:00
|
|
|
write_size = err;
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
if (err == 0) {
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
2014-02-03 10:08:15 +02:00
|
|
|
}
|
2014-04-15 14:28:25 +03:00
|
|
|
break;
|
2014-02-11 20:05:09 +02:00
|
|
|
#endif /* HAVE_LZ4 */
|
2014-04-15 14:28:25 +03:00
|
|
|
#ifdef HAVE_LZO
|
|
|
|
case PAGE_LZO_ALGORITHM:
|
|
|
|
err = lzo1x_1_15_compress(
|
2017-05-20 21:49:35 +03:00
|
|
|
buf, len, out_buf+header_len, &write_size, out_buf+UNIV_PAGE_SIZE);
|
2014-04-15 14:28:25 +03:00
|
|
|
|
2014-04-23 19:23:11 +03:00
|
|
|
if (err != LZO_E_OK || write_size > UNIV_PAGE_SIZE-header_len) {
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
2014-04-15 14:28:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
#endif /* HAVE_LZO */
|
2014-07-21 22:21:30 +03:00
|
|
|
#ifdef HAVE_LZMA
|
|
|
|
case PAGE_LZMA_ALGORITHM: {
|
|
|
|
size_t out_pos=0;
|
|
|
|
|
|
|
|
err = lzma_easy_buffer_encode(
|
2015-06-03 13:10:18 +03:00
|
|
|
comp_level,
|
2014-07-21 22:21:30 +03:00
|
|
|
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,
|
2014-08-07 13:44:00 +03:00
|
|
|
(size_t)write_size);
|
2014-07-21 22:21:30 +03:00
|
|
|
|
2014-08-07 13:44:00 +03:00
|
|
|
if (err != LZMA_OK || out_pos > UNIV_PAGE_SIZE-header_len) {
|
2016-08-12 11:17:45 +03:00
|
|
|
write_size = out_pos;
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
2014-07-21 22:21:30 +03:00
|
|
|
}
|
2014-08-07 13:44:00 +03:00
|
|
|
|
|
|
|
write_size = out_pos;
|
|
|
|
|
2014-07-21 22:21:30 +03:00
|
|
|
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 > UNIV_PAGE_SIZE-header_len) {
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
2014-07-21 22:21:30 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_BZIP2 */
|
|
|
|
|
2015-02-19 17:42:18 +02:00
|
|
|
#ifdef HAVE_SNAPPY
|
|
|
|
case PAGE_SNAPPY_ALGORITHM:
|
|
|
|
{
|
|
|
|
snappy_status cstatus;
|
2017-05-20 21:49:35 +03:00
|
|
|
write_size = snappy_max_compressed_length(UNIV_PAGE_SIZE);
|
2015-02-19 17:42:18 +02:00
|
|
|
|
2015-10-28 09:14:22 +02:00
|
|
|
cstatus = snappy_compress(
|
|
|
|
(const char *)buf,
|
|
|
|
(size_t)len,
|
|
|
|
(char *)(out_buf+header_len),
|
|
|
|
(size_t*)&write_size);
|
2015-02-19 17:42:18 +02:00
|
|
|
|
|
|
|
if (cstatus != SNAPPY_OK || write_size > UNIV_PAGE_SIZE-header_len) {
|
2016-08-12 11:17:45 +03:00
|
|
|
err = (int)cstatus;
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
2015-02-19 17:42:18 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_SNAPPY */
|
|
|
|
|
2014-04-15 14:28:25 +03:00
|
|
|
case PAGE_ZLIB_ALGORITHM:
|
2017-04-21 08:45:48 +03:00
|
|
|
err = compress2(out_buf+header_len, (ulong*)&write_size, buf,
|
|
|
|
uLong(len), comp_level);
|
2014-02-03 10:08:15 +02:00
|
|
|
|
|
|
|
if (err != Z_OK) {
|
2015-09-21 11:24:08 +03:00
|
|
|
goto err_exit;
|
2014-02-03 10:08:15 +02:00
|
|
|
}
|
2014-04-15 14:28:25 +03:00
|
|
|
break;
|
|
|
|
|
2014-06-25 08:46:54 +03:00
|
|
|
case PAGE_UNCOMPRESSED:
|
|
|
|
*out_len = len;
|
|
|
|
return (buf);
|
|
|
|
break;
|
2014-04-15 14:28:25 +03:00
|
|
|
default:
|
|
|
|
ut_error;
|
|
|
|
break;
|
2014-02-03 10:08:15 +02:00
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
/* 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);
|
2015-06-03 13:10:18 +03:00
|
|
|
|
|
|
|
/* Set up the compression algorithm */
|
2014-12-22 16:53:17 +02:00
|
|
|
mach_write_to_8(out_buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, comp_method);
|
2015-06-03 13:10:18 +03:00
|
|
|
|
|
|
|
if (encrypted) {
|
|
|
|
/* Set up the correct page type */
|
|
|
|
mach_write_to_2(out_buf+FIL_PAGE_TYPE, FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
|
|
|
|
mach_write_to_2(out_buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE, comp_method);
|
|
|
|
} else {
|
|
|
|
/* Set up the correct page type */
|
|
|
|
mach_write_to_2(out_buf+FIL_PAGE_TYPE, FIL_PAGE_PAGE_COMPRESSED);
|
|
|
|
}
|
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
/* Set up the actual payload lenght */
|
|
|
|
mach_write_to_2(out_buf+FIL_PAGE_DATA, write_size);
|
2013-12-19 14:36:38 +02:00
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
2014-02-03 10:08:15 +02:00
|
|
|
/* Verify */
|
2015-06-03 13:10:18 +03:00
|
|
|
ut_ad(fil_page_is_compressed(out_buf) || fil_page_is_compressed_encrypted(out_buf));
|
2014-02-03 10:08:15 +02:00
|
|
|
ut_ad(mach_read_from_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM) == BUF_NO_CHECKSUM_MAGIC);
|
|
|
|
ut_ad(mach_read_from_2(out_buf+FIL_PAGE_DATA) == write_size);
|
2015-06-03 13:10:18 +03:00
|
|
|
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);
|
2014-07-31 11:31:39 +03:00
|
|
|
|
|
|
|
/* Verify that page can be decompressed */
|
|
|
|
{
|
|
|
|
byte *comp_page;
|
|
|
|
byte *uncomp_page;
|
|
|
|
|
2016-08-12 11:17:45 +03:00
|
|
|
comp_page = static_cast<byte *>(ut_malloc_nokey(UNIV_PAGE_SIZE));
|
|
|
|
uncomp_page = static_cast<byte *>(ut_malloc_nokey(UNIV_PAGE_SIZE));
|
2014-07-31 11:31:39 +03:00
|
|
|
memcpy(comp_page, out_buf, UNIV_PAGE_SIZE);
|
|
|
|
|
2017-04-21 08:45:48 +03:00
|
|
|
fil_decompress_page(uncomp_page, comp_page, ulong(len), NULL);
|
2015-09-21 11:24:08 +03:00
|
|
|
|
2017-04-21 11:28:18 +03:00
|
|
|
if (buf_page_is_corrupted(false, uncomp_page, univ_page_size,
|
|
|
|
space)) {
|
|
|
|
buf_page_print(uncomp_page, univ_page_size, 0);
|
2014-07-31 11:31:39 +03:00
|
|
|
}
|
2015-09-21 11:24:08 +03:00
|
|
|
|
2014-07-31 11:31:39 +03:00
|
|
|
ut_free(comp_page);
|
|
|
|
ut_free(uncomp_page);
|
|
|
|
}
|
2014-02-11 20:05:09 +02:00
|
|
|
#endif /* UNIV_DEBUG */
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
write_size+=header_len;
|
2014-02-21 10:20:18 +02:00
|
|
|
|
2015-06-30 08:34:31 +03:00
|
|
|
if (block_size <= 0) {
|
|
|
|
block_size = 512;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(write_size > 0 && block_size > 0);
|
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
/* Actual write needs to be alligned on block size */
|
2014-10-28 14:49:31 +04:00
|
|
|
if (write_size % block_size) {
|
2014-11-04 12:26:48 +02:00
|
|
|
size_t tmp = write_size;
|
|
|
|
write_size = (size_t)ut_uint64_align_up((ib_uint64_t)write_size, block_size);
|
2015-09-21 11:24:08 +03:00
|
|
|
/* Clean up the end of buffer */
|
|
|
|
memset(out_buf+tmp, 0, write_size - tmp);
|
2014-11-04 12:26:48 +02:00
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
ut_a(write_size > 0 && ((write_size % block_size) == 0));
|
|
|
|
ut_a(write_size >= tmp);
|
|
|
|
#endif
|
2014-02-03 10:08:15 +02:00
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2017-04-21 11:28:18 +03:00
|
|
|
DBUG_LOG("compress", "Succeeded for space "
|
|
|
|
<< (space ? space->id : 0) << " '"
|
|
|
|
<< (space ? space->name : "(import)")
|
|
|
|
<< "' len " << len << " out_len " << write_size);
|
2014-02-03 10:08:15 +02:00
|
|
|
|
|
|
|
srv_stats.page_compression_saved.add((len - write_size));
|
|
|
|
srv_stats.pages_page_compressed.inc();
|
2014-11-24 10:01:49 +02:00
|
|
|
|
2014-12-04 12:40:19 +02:00
|
|
|
/* If we do not persistently trim rest of page, we need to write it
|
|
|
|
all */
|
|
|
|
if (!srv_use_trim) {
|
2015-09-21 11:24:08 +03:00
|
|
|
memset(out_buf+write_size,0,len-write_size);
|
2014-12-04 12:40:19 +02:00
|
|
|
write_size = len;
|
|
|
|
}
|
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
*out_len = write_size;
|
|
|
|
|
2015-09-21 11:24:08 +03:00
|
|
|
if (allocated) {
|
|
|
|
/* TODO: reduce number of memcpy's */
|
|
|
|
memcpy(buf, out_buf, len);
|
2017-01-25 08:43:19 +02:00
|
|
|
goto exit_free;
|
2015-09-21 11:24:08 +03:00
|
|
|
} else {
|
|
|
|
return(out_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
err_exit:
|
2016-08-12 11:17:45 +03:00
|
|
|
/* If error we leave the actual page as it was */
|
|
|
|
|
|
|
|
#ifndef UNIV_PAGECOMPRESS_DEBUG
|
2017-04-21 18:29:50 +03:00
|
|
|
if (space && !space->printed_compression_failure) {
|
|
|
|
space->printed_compression_failure = true;
|
2016-08-12 11:17:45 +03:00
|
|
|
#endif
|
|
|
|
ib::warn() << "Compression failed for space: "
|
2017-04-21 11:28:18 +03:00
|
|
|
<< space->id << " name: "
|
|
|
|
<< space->name << " len: "
|
2016-08-12 11:17:45 +03:00
|
|
|
<< 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;
|
|
|
|
|
2017-01-25 08:43:19 +02:00
|
|
|
exit_free:
|
2015-09-21 11:24:08 +03:00
|
|
|
if (allocated) {
|
|
|
|
ut_free(out_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (buf);
|
2014-02-03 10:08:15 +02:00
|
|
|
|
2013-12-19 14:36:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************//**
|
|
|
|
For page compressed pages decompress the page after actual read
|
|
|
|
operation. */
|
2015-06-03 13:10:18 +03:00
|
|
|
UNIV_INTERN
|
2013-12-19 14:36:38 +02:00
|
|
|
void
|
|
|
|
fil_decompress_page(
|
|
|
|
/*================*/
|
2015-06-03 13:10:18 +03:00
|
|
|
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.*/
|
2016-04-29 12:32:35 +03:00
|
|
|
ulint* write_size, /*!< in/out: Actual payload size of
|
2015-06-03 13:10:18 +03:00
|
|
|
the compressed data. */
|
2016-04-29 12:32:35 +03:00
|
|
|
bool return_error) /*!< in: true if only an error should
|
|
|
|
be produced when decompression fails.
|
|
|
|
By default this parameter is false. */
|
2013-12-19 14:36:38 +02:00
|
|
|
{
|
2015-06-03 13:10:18 +03:00
|
|
|
int err = 0;
|
|
|
|
ulint actual_size = 0;
|
2017-01-25 10:11:37 +02:00
|
|
|
ib_uint64_t compression_alg = 0;
|
2013-12-19 14:36:38 +02:00
|
|
|
byte *in_buf;
|
2014-07-21 22:21:30 +03:00
|
|
|
ulint ptype;
|
2017-01-16 14:03:36 +02:00
|
|
|
ulint header_len;
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-01-13 15:02:31 +02:00
|
|
|
ut_ad(buf);
|
|
|
|
ut_ad(len);
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-07-21 22:21:30 +03:00
|
|
|
ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
|
|
|
|
|
2017-01-16 14:03:36 +02:00
|
|
|
switch (ptype) {
|
|
|
|
case FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED:
|
|
|
|
header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE
|
|
|
|
+ FIL_PAGE_COMPRESSION_METHOD_SIZE;
|
|
|
|
break;
|
|
|
|
case FIL_PAGE_PAGE_COMPRESSED:
|
|
|
|
header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* The page is not in our format. */
|
2014-07-21 22:21:30 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no buffer was given, we need to allocate temporal buffer
|
|
|
|
if (page_buf == NULL) {
|
2016-08-12 11:17:45 +03:00
|
|
|
in_buf = static_cast<byte *>(ut_malloc_nokey(UNIV_PAGE_SIZE));
|
2015-09-21 11:24:08 +03:00
|
|
|
memset(in_buf, 0, UNIV_PAGE_SIZE);
|
2014-07-21 22:21:30 +03:00
|
|
|
} else {
|
|
|
|
in_buf = page_buf;
|
|
|
|
}
|
|
|
|
|
2013-12-19 14:36:38 +02:00
|
|
|
/* Before actual decompress, make sure that page type is correct */
|
|
|
|
|
2017-05-23 11:09:47 +03:00
|
|
|
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 << ".";
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get compression algorithm */
|
2015-06-03 13:10:18 +03:00
|
|
|
if (ptype == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
|
2017-01-25 10:11:37 +02:00
|
|
|
compression_alg = static_cast<ib_uint64_t>(mach_read_from_2(buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE));
|
2015-06-03 13:10:18 +03:00
|
|
|
} else {
|
|
|
|
compression_alg = mach_read_from_8(buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
|
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-02-03 10:08:15 +02:00
|
|
|
/* 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) {
|
2016-08-12 11:17:45 +03:00
|
|
|
ib::error() << "Corruption: We try to uncompress corrupted page"
|
|
|
|
<< " actual size: " << actual_size
|
|
|
|
<< " compression method: "
|
|
|
|
<< fil_get_compression_alg_name(compression_alg)
|
|
|
|
<< ".";
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2014-02-03 10:08:15 +02:00
|
|
|
ut_error;
|
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-03-04 17:14:08 +02:00
|
|
|
/* Store actual payload size of the compressed data. This pointer
|
|
|
|
points to buffer pool. */
|
|
|
|
if (write_size) {
|
|
|
|
*write_size = actual_size;
|
|
|
|
}
|
|
|
|
|
2017-01-12 13:30:10 +02:00
|
|
|
DBUG_LOG("compress", "Preparing for decompress for len "
|
|
|
|
<< actual_size << ".");
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-04-15 14:28:25 +03:00
|
|
|
switch(compression_alg) {
|
|
|
|
case PAGE_ZLIB_ALGORITHM:
|
2015-06-03 13:10:18 +03:00
|
|
|
err= uncompress(in_buf, &len, buf+header_len, (unsigned long)actual_size);
|
2013-12-19 14:36:38 +02:00
|
|
|
|
|
|
|
/* If uncompress fails it means that page is corrupted */
|
|
|
|
if (err != Z_OK) {
|
2016-08-12 11:17:45 +03:00
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
}
|
2014-04-15 14:28:25 +03:00
|
|
|
break;
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-02-11 20:05:09 +02:00
|
|
|
#ifdef HAVE_LZ4
|
2014-04-15 14:28:25 +03:00
|
|
|
case PAGE_LZ4_ALGORITHM:
|
2015-06-03 13:10:18 +03:00
|
|
|
err = LZ4_decompress_fast((const char *)buf+header_len, (char *)in_buf, len);
|
2013-12-19 14:36:38 +02:00
|
|
|
|
2014-02-11 20:05:09 +02:00
|
|
|
if (err != (int)actual_size) {
|
2016-08-12 11:17:45 +03:00
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2013-12-19 14:36:38 +02:00
|
|
|
}
|
2014-04-15 14:28:25 +03:00
|
|
|
break;
|
2014-02-11 20:05:09 +02:00
|
|
|
#endif /* HAVE_LZ4 */
|
2014-04-15 14:28:25 +03:00
|
|
|
#ifdef HAVE_LZO
|
2015-06-03 13:10:18 +03:00
|
|
|
case PAGE_LZO_ALGORITHM: {
|
2017-05-20 21:49:35 +03:00
|
|
|
ulint olen = 0;
|
2015-06-03 13:10:18 +03:00
|
|
|
err = lzo1x_decompress((const unsigned char *)buf+header_len,
|
2014-04-15 14:28:25 +03:00
|
|
|
actual_size,(unsigned char *)in_buf, &olen, NULL);
|
|
|
|
|
|
|
|
if (err != LZO_E_OK || (olen == 0 || olen > UNIV_PAGE_SIZE)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
len = olen;
|
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2014-04-15 14:28:25 +03:00
|
|
|
}
|
|
|
|
break;
|
2014-10-07 11:39:42 +03:00
|
|
|
}
|
2014-07-21 22:21:30 +03:00
|
|
|
#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,
|
2015-06-03 13:10:18 +03:00
|
|
|
buf+header_len,
|
2014-07-21 22:21:30 +03:00
|
|
|
&src_pos,
|
|
|
|
actual_size,
|
|
|
|
in_buf,
|
|
|
|
&dst_pos,
|
|
|
|
len);
|
|
|
|
|
|
|
|
|
|
|
|
if (ret != LZMA_OK || (dst_pos == 0 || dst_pos > UNIV_PAGE_SIZE)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
len = dst_pos;
|
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2014-07-21 22:21:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_LZMA */
|
|
|
|
#ifdef HAVE_BZIP2
|
|
|
|
case PAGE_BZIP2_ALGORITHM: {
|
|
|
|
unsigned int dst_pos = UNIV_PAGE_SIZE;
|
|
|
|
|
|
|
|
err = BZ2_bzBuffToBuffDecompress(
|
|
|
|
(char *)in_buf,
|
|
|
|
&dst_pos,
|
2015-06-03 13:10:18 +03:00
|
|
|
(char *)(buf+header_len),
|
2014-07-21 22:21:30 +03:00
|
|
|
actual_size,
|
|
|
|
1,
|
|
|
|
0);
|
|
|
|
|
|
|
|
if (err != BZ_OK || (dst_pos == 0 || dst_pos > UNIV_PAGE_SIZE)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
len = dst_pos;
|
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2014-07-21 22:21:30 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_BZIP2 */
|
2015-02-19 17:42:18 +02:00
|
|
|
#ifdef HAVE_SNAPPY
|
|
|
|
case PAGE_SNAPPY_ALGORITHM:
|
|
|
|
{
|
|
|
|
snappy_status cstatus;
|
2017-05-20 21:49:35 +03:00
|
|
|
ulint olen = UNIV_PAGE_SIZE;
|
2015-02-19 17:42:18 +02:00
|
|
|
|
|
|
|
cstatus = snappy_uncompress(
|
2015-06-03 13:10:18 +03:00
|
|
|
(const char *)(buf+header_len),
|
2015-10-28 09:14:22 +02:00
|
|
|
(size_t)actual_size,
|
2015-02-19 17:42:18 +02:00
|
|
|
(char *)in_buf,
|
2015-10-28 09:14:22 +02:00
|
|
|
(size_t*)&olen);
|
2015-02-19 17:42:18 +02:00
|
|
|
|
|
|
|
if (cstatus != SNAPPY_OK || (olen == 0 || olen > UNIV_PAGE_SIZE)) {
|
2016-08-12 11:17:45 +03:00
|
|
|
err = (int)cstatus;
|
|
|
|
len = olen;
|
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2015-02-19 17:42:18 +02:00
|
|
|
}
|
2017-05-20 21:49:35 +03:00
|
|
|
|
2015-02-19 17:42:18 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_SNAPPY */
|
2014-04-15 14:28:25 +03:00
|
|
|
default:
|
2016-08-12 11:17:45 +03:00
|
|
|
goto err_exit;
|
2016-04-29 12:32:35 +03:00
|
|
|
if (return_error) {
|
|
|
|
goto error_return;
|
|
|
|
}
|
2014-04-15 14:28:25 +03:00
|
|
|
break;
|
2013-12-19 14:36:38 +02:00
|
|
|
}
|
2014-02-03 10:08:15 +02:00
|
|
|
|
|
|
|
srv_stats.pages_page_decompressed.inc();
|
|
|
|
|
|
|
|
/* Copy the uncompressed page to the buffer pool, not
|
|
|
|
really any other options. */
|
|
|
|
memcpy(buf, in_buf, len);
|
|
|
|
|
2016-04-29 12:32:35 +03:00
|
|
|
error_return:
|
2017-05-20 21:49:35 +03:00
|
|
|
if (page_buf != in_buf) {
|
2014-02-03 10:08:15 +02:00
|
|
|
ut_free(in_buf);
|
|
|
|
}
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
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);
|
2017-04-28 12:23:35 +03:00
|
|
|
fil_space_t* space = fil_space_acquire_for_io(space_id);
|
2016-08-12 11:17:45 +03:00
|
|
|
|
|
|
|
ib::error() << "Corruption: Page is marked as compressed"
|
|
|
|
<< " space: " << space_id << " name: "
|
2017-04-28 12:23:35 +03:00
|
|
|
<< (space ? space->name : "NULL")
|
2016-08-12 11:17:45 +03:00
|
|
|
<< " but uncompress failed with error: " << err
|
|
|
|
<< " size: " << actual_size
|
|
|
|
<< " len: " << len
|
|
|
|
<< " compression method: "
|
|
|
|
<< fil_get_compression_alg_name(compression_alg) << ".";
|
|
|
|
|
2017-04-21 11:28:18 +03:00
|
|
|
buf_page_print(buf, univ_page_size, 0);
|
2017-04-28 12:23:35 +03:00
|
|
|
fil_space_release_for_io(space);
|
2013-12-19 14:36:38 +02:00
|
|
|
}
|