MDEV-13103 Deal with page_compressed page corruption
fil_page_decompress(): Replaces fil_decompress_page(). Allow the caller detect errors. Remove duplicated code. Use the "safe" instead of "fast" variants of decompression routines. fil_page_compress(): Replaces fil_compress_page(). The length of the input buffer always was srv_page_size (innodb_page_size). Remove printouts, and remove the fil_space_t* parameter. buf_tmp_buffer_t::reserved: Make private; the accessors acquire() and release() will use atomic memory access. buf_pool_reserve_tmp_slot(): Make static. Remove the second parameter. Do not acquire any mutex. Remove the allocation of the buffers. buf_tmp_reserve_crypt_buf(), buf_tmp_reserve_compression_buf(): Refactored away from buf_pool_reserve_tmp_slot(). buf_page_decrypt_after_read(): Make static, and simplify the logic. Use the encryption buffer also for decompressing. buf_page_io_complete(), buf_dblwr_process(): Check more failures. fil_space_encrypt(): Simplify the debug checks. fil_space_t::printed_compression_failure: Remove. fil_get_compression_alg_name(): Remove. fil_iterate(): Allocate a buffer for compression and decompression only once, instead of allocating and freeing it for every page that uses compression, during IMPORT TABLESPACE. fil_node_get_space_id(), fil_page_is_index_page(), fil_page_is_lzo_compressed(): Remove (unused code).
This commit is contained in:
parent
72005b7a1c
commit
f5eb37129f
@ -1,4 +1,3 @@
|
||||
call mtr.add_suppression("InnoDB: Compression failed for space [0-9]+ name test/innodb_page_compressed[0-9] len [0-9]+ err 2 write_size [0-9]+.");
|
||||
set global innodb_file_format = `Barracuda`;
|
||||
set global innodb_file_per_table = on;
|
||||
create table innodb_normal (c1 int not null auto_increment primary key, b char(200)) engine=innodb;
|
||||
|
@ -1,4 +1,3 @@
|
||||
call mtr.add_suppression("InnoDB: Compression failed for space [0-9]+ name test/innodb_page_compressed[0-9] len [0-9]+ err 2 write_size [0-9]+.");
|
||||
set global innodb_compression_algorithm = snappy;
|
||||
set global innodb_file_format = `Barracuda`;
|
||||
set global innodb_file_per_table = on;
|
||||
|
@ -1,8 +1,6 @@
|
||||
--source include/have_innodb.inc
|
||||
--source include/not_embedded.inc
|
||||
|
||||
call mtr.add_suppression("InnoDB: Compression failed for space [0-9]+ name test/innodb_page_compressed[0-9] len [0-9]+ err 2 write_size [0-9]+.");
|
||||
|
||||
# All page compression test use the same
|
||||
--source include/innodb-page-compression.inc
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
-- source include/have_innodb_snappy.inc
|
||||
--source include/not_embedded.inc
|
||||
|
||||
call mtr.add_suppression("InnoDB: Compression failed for space [0-9]+ name test/innodb_page_compressed[0-9] len [0-9]+ err 2 write_size [0-9]+.");
|
||||
|
||||
# snappy
|
||||
set global innodb_compression_algorithm = snappy;
|
||||
|
||||
|
@ -354,14 +354,142 @@ on the io_type */
|
||||
? (counter##_READ) \
|
||||
: (counter##_WRITTEN))
|
||||
|
||||
|
||||
/** Reserve a buffer slot for encryption, decryption or page compression.
|
||||
@param[in,out] buf_pool buffer pool
|
||||
@return reserved buffer slot */
|
||||
static buf_tmp_buffer_t* buf_pool_reserve_tmp_slot(buf_pool_t* buf_pool)
|
||||
{
|
||||
for (ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
|
||||
buf_tmp_buffer_t* slot = &buf_pool->tmp_arr->slots[i];
|
||||
if (slot->acquire()) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume that free slot is found */
|
||||
ut_error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Reserve a buffer for encryption, decryption or decompression.
|
||||
@param[in,out] slot reserved slot */
|
||||
static void buf_tmp_reserve_crypt_buf(buf_tmp_buffer_t* slot)
|
||||
{
|
||||
if (!slot->crypt_buf) {
|
||||
slot->crypt_buf = static_cast<byte*>(
|
||||
aligned_malloc(srv_page_size, srv_page_size));
|
||||
}
|
||||
}
|
||||
|
||||
/** Reserve a buffer for compression.
|
||||
@param[in,out] slot reserved slot */
|
||||
static void buf_tmp_reserve_compression_buf(buf_tmp_buffer_t* slot)
|
||||
{
|
||||
if (!slot->comp_buf) {
|
||||
/* Both snappy and lzo compression methods require that
|
||||
output buffer used for compression is bigger than input
|
||||
buffer. Increase the allocated buffer size accordingly. */
|
||||
ulint size = srv_page_size;
|
||||
#ifdef HAVE_LZO
|
||||
size += LZO1X_1_15_MEM_COMPRESS;
|
||||
#elif defined HAVE_SNAPPY
|
||||
size = snappy_max_compressed_length(size);
|
||||
#endif
|
||||
slot->comp_buf = static_cast<byte*>(
|
||||
aligned_malloc(size, srv_page_size));
|
||||
}
|
||||
}
|
||||
|
||||
/** Decrypt a page.
|
||||
@param[in,out] bpage Page control block
|
||||
@param[in,out] space tablespace
|
||||
@return whether the operation was successful */
|
||||
static
|
||||
bool
|
||||
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
static bool buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
|
||||
{
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
ut_ad(space->id == bpage->space);
|
||||
|
||||
byte* dst_frame = bpage->zip.data ? bpage->zip.data :
|
||||
((buf_block_t*) bpage)->frame;
|
||||
bool page_compressed = fil_page_is_compressed(dst_frame);
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
|
||||
if (bpage->offset == 0) {
|
||||
/* File header pages are not encrypted/compressed */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Page is encrypted if encryption information is found from
|
||||
tablespace and page contains used key_version. This is true
|
||||
also for pages first compressed and then encrypted. */
|
||||
|
||||
buf_tmp_buffer_t* slot;
|
||||
|
||||
if (page_compressed) {
|
||||
/* the page we read is unencrypted */
|
||||
/* Find free slot from temporary memory array */
|
||||
decompress:
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool);
|
||||
/* For decompression, use crypt_buf. */
|
||||
buf_tmp_reserve_crypt_buf(slot);
|
||||
decompress_with_slot:
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
bpage->write_size = fil_page_decompress(slot->crypt_buf,
|
||||
dst_frame);
|
||||
slot->release();
|
||||
|
||||
ut_ad(!bpage->write_size || fil_page_type_validate(dst_frame));
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
return bpage->write_size != 0;
|
||||
}
|
||||
|
||||
if (space->crypt_data
|
||||
&& mach_read_from_4(FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
|
||||
+ dst_frame)) {
|
||||
/* Verify encryption checksum before we even try to
|
||||
decrypt. */
|
||||
if (!fil_space_verify_crypt_checksum(
|
||||
dst_frame, buf_page_get_zip_size(bpage), NULL,
|
||||
bpage->offset)) {
|
||||
decrypt_failed:
|
||||
/* Mark page encrypted in case it should be. */
|
||||
if (space->crypt_data->type
|
||||
!= CRYPT_SCHEME_UNENCRYPTED) {
|
||||
bpage->encrypted = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find free slot from temporary memory array */
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool);
|
||||
buf_tmp_reserve_crypt_buf(slot);
|
||||
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
/* decrypt using crypt_buf to dst_frame */
|
||||
if (!fil_space_decrypt(space, slot->crypt_buf,
|
||||
dst_frame, &bpage->encrypted)) {
|
||||
slot->release();
|
||||
goto decrypt_failed;
|
||||
}
|
||||
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
if (fil_page_is_compressed_encrypted(dst_frame)) {
|
||||
goto decompress_with_slot;
|
||||
}
|
||||
|
||||
slot->release();
|
||||
} else if (fil_page_is_compressed_encrypted(dst_frame)) {
|
||||
goto decompress;
|
||||
}
|
||||
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Mark a table with the specified space pointed by bpage->space corrupted.
|
||||
@ -4784,7 +4912,6 @@ buf_page_io_complete(buf_page_t* bpage, bool evict)
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
const ibool uncompressed = (buf_page_get_state(bpage)
|
||||
== BUF_BLOCK_FILE_PAGE);
|
||||
byte* frame = NULL;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
|
||||
ut_a(buf_page_in_file(bpage));
|
||||
@ -4802,19 +4929,18 @@ buf_page_io_complete(buf_page_t* bpage, bool evict)
|
||||
ulint read_page_no = 0;
|
||||
ulint read_space_id = 0;
|
||||
uint key_version = 0;
|
||||
|
||||
ut_ad(bpage->zip.data || ((buf_block_t*)bpage)->frame);
|
||||
byte* frame = bpage->zip.data
|
||||
? bpage->zip.data
|
||||
: reinterpret_cast<buf_block_t*>(bpage)->frame;
|
||||
ut_ad(frame);
|
||||
fil_space_t* space = fil_space_acquire_for_io(bpage->space);
|
||||
if (!space) {
|
||||
return(DB_TABLESPACE_DELETED);
|
||||
}
|
||||
|
||||
buf_page_decrypt_after_read(bpage, space);
|
||||
|
||||
if (buf_page_get_zip_size(bpage)) {
|
||||
frame = bpage->zip.data;
|
||||
} else {
|
||||
frame = ((buf_block_t*) bpage)->frame;
|
||||
if (!buf_page_decrypt_after_read(bpage, space)) {
|
||||
err = DB_DECRYPTION_FAILED;
|
||||
goto database_corrupted;
|
||||
}
|
||||
|
||||
if (buf_page_get_zip_size(bpage)) {
|
||||
@ -4978,7 +5104,7 @@ database_corrupted:
|
||||
/* io_type == BUF_IO_WRITE */
|
||||
if (bpage->slot) {
|
||||
/* Mark slot free */
|
||||
bpage->slot->reserved = false;
|
||||
bpage->slot->release();
|
||||
bpage->slot = NULL;
|
||||
}
|
||||
}
|
||||
@ -6233,66 +6359,6 @@ buf_page_init_for_backup_restore(
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
/********************************************************************//**
|
||||
Reserve unused slot from temporary memory array and allocate necessary
|
||||
temporary memory if not yet allocated.
|
||||
@return reserved slot */
|
||||
UNIV_INTERN
|
||||
buf_tmp_buffer_t*
|
||||
buf_pool_reserve_tmp_slot(
|
||||
/*======================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool where to
|
||||
reserve */
|
||||
bool compressed) /*!< in: is file space compressed */
|
||||
{
|
||||
buf_tmp_buffer_t *free_slot=NULL;
|
||||
|
||||
/* Array is protected by buf_pool mutex */
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
|
||||
for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
|
||||
buf_tmp_buffer_t *slot = &buf_pool->tmp_arr->slots[i];
|
||||
|
||||
if(slot->reserved == false) {
|
||||
free_slot = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume that free slot is found */
|
||||
ut_a(free_slot != NULL);
|
||||
free_slot->reserved = true;
|
||||
/* Now that we have reserved this slot we can release
|
||||
buf_pool mutex */
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
|
||||
/* Allocate temporary memory for encryption/decryption */
|
||||
if (free_slot->crypt_buf == NULL) {
|
||||
free_slot->crypt_buf = static_cast<byte*>(aligned_malloc(UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
|
||||
memset(free_slot->crypt_buf, 0, UNIV_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* For page compressed tables allocate temporary memory for
|
||||
compression/decompression */
|
||||
if (compressed && free_slot->comp_buf == NULL) {
|
||||
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
|
||||
size = snappy_max_compressed_length(size);
|
||||
#endif
|
||||
#if HAVE_LZO
|
||||
size += LZO1X_1_15_MEM_COMPRESS;
|
||||
#endif
|
||||
free_slot->comp_buf = static_cast<byte*>(aligned_malloc(size, UNIV_PAGE_SIZE));
|
||||
memset(free_slot->comp_buf, 0, size);
|
||||
}
|
||||
|
||||
return (free_slot);
|
||||
}
|
||||
|
||||
/** Encryption and page_compression hook that is called just before
|
||||
a page is written to disk.
|
||||
@param[in,out] space tablespace
|
||||
@ -6342,16 +6408,18 @@ buf_page_encrypt_before_write(
|
||||
}
|
||||
|
||||
ulint zip_size = buf_page_get_zip_size(bpage);
|
||||
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
|
||||
ut_ad(!zip_size || !page_compressed);
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
/* Find free slot from temporary memory array */
|
||||
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool);
|
||||
slot->out_buf = NULL;
|
||||
bpage->slot = slot;
|
||||
|
||||
buf_tmp_reserve_crypt_buf(slot);
|
||||
byte *dst_frame = slot->crypt_buf;
|
||||
|
||||
if (!page_compressed) {
|
||||
not_compressed:
|
||||
/* Encrypt page content */
|
||||
byte* tmp = fil_space_encrypt(space,
|
||||
bpage->offset,
|
||||
@ -6359,32 +6427,28 @@ buf_page_encrypt_before_write(
|
||||
src_frame,
|
||||
dst_frame);
|
||||
|
||||
bpage->real_size = page_size;
|
||||
bpage->real_size = UNIV_PAGE_SIZE;
|
||||
slot->out_buf = dst_frame = tmp;
|
||||
|
||||
ut_d(fil_page_type_validate(tmp));
|
||||
} else {
|
||||
/* First we compress the page content */
|
||||
ulint out_len = 0;
|
||||
|
||||
byte *tmp = fil_compress_page(
|
||||
space,
|
||||
(byte *)src_frame,
|
||||
slot->comp_buf,
|
||||
page_size,
|
||||
buf_tmp_reserve_compression_buf(slot);
|
||||
byte* tmp = slot->comp_buf;
|
||||
ulint out_len = fil_page_compress(
|
||||
src_frame, tmp,
|
||||
fsp_flags_get_page_compression_level(space->flags),
|
||||
fil_space_get_block_size(space, bpage->offset),
|
||||
encrypted,
|
||||
&out_len);
|
||||
encrypted);
|
||||
if (!out_len) {
|
||||
goto not_compressed;
|
||||
}
|
||||
|
||||
bpage->real_size = out_len;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(tmp);
|
||||
#endif
|
||||
|
||||
if(encrypted) {
|
||||
ut_d(fil_page_type_validate(tmp));
|
||||
|
||||
if (encrypted) {
|
||||
/* And then we encrypt the page content */
|
||||
tmp = fil_space_encrypt(space,
|
||||
bpage->offset,
|
||||
@ -6396,131 +6460,9 @@ buf_page_encrypt_before_write(
|
||||
slot->out_buf = dst_frame = tmp;
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
// return dst_frame which will be written
|
||||
return dst_frame;
|
||||
}
|
||||
|
||||
/** Decrypt a page.
|
||||
@param[in,out] bpage Page control block
|
||||
@param[in,out] space tablespace
|
||||
@return whether the operation was successful */
|
||||
static
|
||||
bool
|
||||
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
|
||||
{
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
ut_ad(space->id == bpage->space);
|
||||
|
||||
ulint zip_size = buf_page_get_zip_size(bpage);
|
||||
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
|
||||
|
||||
byte* dst_frame = (zip_size) ? bpage->zip.data :
|
||||
((buf_block_t*) bpage)->frame;
|
||||
unsigned key_version =
|
||||
mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
|
||||
bool page_compressed = fil_page_is_compressed(dst_frame);
|
||||
bool page_compressed_encrypted = fil_page_is_compressed_encrypted(dst_frame);
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
bool success = true;
|
||||
|
||||
if (bpage->offset == 0) {
|
||||
/* File header pages are not encrypted/compressed */
|
||||
return (true);
|
||||
}
|
||||
|
||||
/* Page is encrypted if encryption information is found from
|
||||
tablespace and page contains used key_version. This is true
|
||||
also for pages first compressed and then encrypted. */
|
||||
if (!space->crypt_data) {
|
||||
key_version = 0;
|
||||
}
|
||||
|
||||
if (page_compressed) {
|
||||
/* the page we read is unencrypted */
|
||||
/* Find free slot from temporary memory array */
|
||||
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
|
||||
/* decompress using comp_buf to dst_frame */
|
||||
fil_decompress_page(slot->comp_buf,
|
||||
dst_frame,
|
||||
ulong(size),
|
||||
&bpage->write_size);
|
||||
|
||||
/* Mark this slot as free */
|
||||
slot->reserved = false;
|
||||
key_version = 0;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
} else {
|
||||
buf_tmp_buffer_t* slot = NULL;
|
||||
|
||||
if (key_version) {
|
||||
/* Verify encryption checksum before we even try to
|
||||
decrypt. */
|
||||
if (!fil_space_verify_crypt_checksum(dst_frame,
|
||||
zip_size, NULL, bpage->offset)) {
|
||||
|
||||
/* Mark page encrypted in case it should
|
||||
be. */
|
||||
if (space->crypt_data->type
|
||||
!= CRYPT_SCHEME_UNENCRYPTED) {
|
||||
bpage->encrypted = true;
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
/* Find free slot from temporary memory array */
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
|
||||
/* decrypt using crypt_buf to dst_frame */
|
||||
if (!fil_space_decrypt(space, slot->crypt_buf,
|
||||
dst_frame, &bpage->encrypted)) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (page_compressed_encrypted && success) {
|
||||
if (!slot) {
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
/* decompress using comp_buf to dst_frame */
|
||||
fil_decompress_page(slot->comp_buf,
|
||||
dst_frame,
|
||||
ulong(size),
|
||||
&bpage->write_size);
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
}
|
||||
|
||||
/* Mark this slot as free */
|
||||
if (slot) {
|
||||
slot->reserved = false;
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
return (success);
|
||||
}
|
||||
#endif /* !UNIV_INNOCHECKSUM */
|
||||
|
@ -510,10 +510,11 @@ buf_dblwr_process()
|
||||
"Restoring possible half-written data pages "
|
||||
"from the doublewrite buffer...");
|
||||
|
||||
unaligned_read_buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
|
||||
unaligned_read_buf = static_cast<byte*>(ut_malloc(3 * UNIV_PAGE_SIZE));
|
||||
|
||||
read_buf = static_cast<byte*>(
|
||||
ut_align(unaligned_read_buf, UNIV_PAGE_SIZE));
|
||||
byte* const buf = read_buf + UNIV_PAGE_SIZE;
|
||||
|
||||
for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
|
||||
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
|
||||
@ -562,24 +563,23 @@ buf_dblwr_process()
|
||||
ignore this page (there should be redo log
|
||||
records to initialize it). */
|
||||
} else {
|
||||
if (fil_page_is_compressed_encrypted(read_buf) ||
|
||||
fil_page_is_compressed(read_buf)) {
|
||||
/* Decompress the page before
|
||||
validating the checksum. */
|
||||
fil_decompress_page(
|
||||
NULL, read_buf, srv_page_size,
|
||||
NULL, true);
|
||||
/* Decompress the page before
|
||||
validating the checksum. */
|
||||
ulint decomp = fil_page_decompress(buf, read_buf);
|
||||
if (!decomp || (decomp != srv_page_size && zip_size)) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (fil_space_verify_crypt_checksum(
|
||||
read_buf, zip_size, NULL, page_no)
|
||||
|| !buf_page_is_corrupted(
|
||||
true, read_buf, zip_size, space())) {
|
||||
read_buf, zip_size, NULL, page_no)
|
||||
|| !buf_page_is_corrupted(
|
||||
true, read_buf, zip_size, space())) {
|
||||
/* The page is good; there is no need
|
||||
to consult the doublewrite buffer. */
|
||||
continue;
|
||||
}
|
||||
|
||||
bad:
|
||||
/* We intentionally skip this message for
|
||||
is_all_zero pages. */
|
||||
ib_logf(IB_LOG_LEVEL_INFO,
|
||||
@ -588,18 +588,15 @@ buf_dblwr_process()
|
||||
space_id, page_no);
|
||||
}
|
||||
|
||||
/* Next, validate the doublewrite page. */
|
||||
if (fil_page_is_compressed_encrypted(page) ||
|
||||
fil_page_is_compressed(page)) {
|
||||
/* Decompress the page before
|
||||
validating the checksum. */
|
||||
fil_decompress_page(
|
||||
NULL, page, srv_page_size, NULL, true);
|
||||
ulint decomp = fil_page_decompress(buf, page);
|
||||
if (!decomp || (decomp != srv_page_size && zip_size)) {
|
||||
goto bad_doublewrite;
|
||||
}
|
||||
|
||||
if (!fil_space_verify_crypt_checksum(page, zip_size, NULL, page_no)
|
||||
if (!fil_space_verify_crypt_checksum(page, zip_size, NULL,
|
||||
page_no)
|
||||
&& buf_page_is_corrupted(true, page, zip_size, space)) {
|
||||
if (!is_all_zero) {
|
||||
bad_doublewrite:
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"A doublewrite copy of page "
|
||||
ULINTPF ":" ULINTPF " is corrupted.",
|
||||
|
@ -708,60 +708,39 @@ fil_space_encrypt(
|
||||
#ifdef UNIV_DEBUG
|
||||
if (tmp) {
|
||||
/* Verify that encrypted buffer is not corrupted */
|
||||
byte* tmp_mem = (byte *)malloc(UNIV_PAGE_SIZE);
|
||||
dberr_t err = DB_SUCCESS;
|
||||
byte* src = src_frame;
|
||||
bool page_compressed_encrypted = (mach_read_from_2(tmp+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
|
||||
byte* comp_mem = NULL;
|
||||
byte* uncomp_mem = NULL;
|
||||
byte uncomp_mem[UNIV_PAGE_SIZE_MAX];
|
||||
byte tmp_mem[UNIV_PAGE_SIZE_MAX];
|
||||
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
|
||||
|
||||
if (page_compressed_encrypted) {
|
||||
comp_mem = (byte *)malloc(UNIV_PAGE_SIZE);
|
||||
uncomp_mem = (byte *)malloc(UNIV_PAGE_SIZE);
|
||||
memcpy(comp_mem, src_frame, UNIV_PAGE_SIZE);
|
||||
fil_decompress_page(uncomp_mem, comp_mem,
|
||||
srv_page_size, NULL);
|
||||
src = uncomp_mem;
|
||||
memcpy(uncomp_mem, src, srv_page_size);
|
||||
ulint unzipped1 = fil_page_decompress(
|
||||
tmp_mem, uncomp_mem);
|
||||
ut_ad(unzipped1);
|
||||
if (unzipped1 != srv_page_size) {
|
||||
src = uncomp_mem;
|
||||
}
|
||||
}
|
||||
|
||||
bool corrupted1 = buf_page_is_corrupted(true, src, zip_size, space);
|
||||
bool ok = fil_space_decrypt(crypt_data, tmp_mem, size, tmp, &err);
|
||||
ut_ad(!buf_page_is_corrupted(true, src, zip_size, space));
|
||||
ut_ad(fil_space_decrypt(crypt_data, tmp_mem, size, tmp, &err));
|
||||
ut_ad(err == DB_SUCCESS);
|
||||
|
||||
/* Need to decompress the page if it was also compressed */
|
||||
if (page_compressed_encrypted) {
|
||||
memcpy(comp_mem, tmp_mem, UNIV_PAGE_SIZE);
|
||||
fil_decompress_page(tmp_mem, comp_mem,
|
||||
srv_page_size, NULL);
|
||||
byte buf[UNIV_PAGE_SIZE_MAX];
|
||||
memcpy(buf, tmp_mem, srv_page_size);
|
||||
ulint unzipped2 = fil_page_decompress(tmp_mem, buf);
|
||||
ut_ad(unzipped2);
|
||||
}
|
||||
|
||||
bool corrupted = buf_page_is_corrupted(true, tmp_mem, zip_size, space);
|
||||
memcpy(tmp_mem+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, src+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8);
|
||||
bool different = memcmp(src, tmp_mem, size);
|
||||
|
||||
if (!ok || corrupted || corrupted1 || err != DB_SUCCESS || different) {
|
||||
fprintf(stderr, "ok %d corrupted %d corrupted1 %d err %d different %d\n",
|
||||
ok , corrupted, corrupted1, err, different);
|
||||
fprintf(stderr, "src_frame\n");
|
||||
buf_page_print(src_frame, zip_size);
|
||||
fprintf(stderr, "encrypted_frame\n");
|
||||
buf_page_print(tmp, zip_size);
|
||||
fprintf(stderr, "decrypted_frame\n");
|
||||
buf_page_print(tmp_mem, zip_size);
|
||||
ut_ad(0);
|
||||
}
|
||||
|
||||
free(tmp_mem);
|
||||
|
||||
if (comp_mem) {
|
||||
free(comp_mem);
|
||||
}
|
||||
|
||||
if (uncomp_mem) {
|
||||
free(uncomp_mem);
|
||||
}
|
||||
memcpy(tmp_mem + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION,
|
||||
src + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8);
|
||||
ut_ad(!memcmp(src, tmp_mem, size));
|
||||
}
|
||||
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
return tmp;
|
||||
|
@ -342,19 +342,6 @@ fil_space_get_by_id(
|
||||
return(space);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Get space id from fil node */
|
||||
ulint
|
||||
fil_node_get_space_id(
|
||||
/*==================*/
|
||||
fil_node_t* node) /*!< in: Compressed node*/
|
||||
{
|
||||
ut_ad(node);
|
||||
ut_ad(node->space);
|
||||
|
||||
return (node->space->id);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Returns the table space by a given name, NULL if not found. */
|
||||
UNIV_INLINE
|
||||
|
@ -80,73 +80,26 @@ static ulint srv_data_read, srv_data_written;
|
||||
#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 */
|
||||
UNIV_INTERN ulint fil_page_compress(const byte* buf, byte* out_buf, ulint level,
|
||||
ulint block_size, bool encrypted)
|
||||
{
|
||||
int err = Z_OK;
|
||||
int comp_level = level;
|
||||
int comp_level = int(level);
|
||||
ulint header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
|
||||
ulint write_size = 0;
|
||||
#if 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 = 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
|
||||
if (comp_method == PAGE_LZO_ALGORITHM) {
|
||||
size += LZO1X_1_15_MEM_COMPRESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
out_buf = static_cast<byte *>(ut_malloc(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)) {
|
||||
@ -154,8 +107,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
|
||||
@ -164,204 +116,113 @@ fil_compress_page(
|
||||
comp_level = page_zip_level;
|
||||
}
|
||||
|
||||
DBUG_PRINT("compress",
|
||||
("Preparing for space " ULINTPF " '%s' len " ULINTPF,
|
||||
space ? space->id : 0,
|
||||
space ? space->name : "(import)",
|
||||
len));
|
||||
ulint write_size = srv_page_size - header_len;
|
||||
|
||||
write_size = UNIV_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
|
||||
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
|
||||
|
||||
#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) {
|
||||
/* 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_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
#ifndef UNIV_PAGECOMPRESS_DEBUG
|
||||
}
|
||||
#endif
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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+UNIV_PAGE_SIZE);
|
||||
case PAGE_LZO_ALGORITHM: {
|
||||
lzo_uint len = write_size;
|
||||
|
||||
write_size = write_size_lzo;
|
||||
|
||||
if (err != LZO_E_OK || write_size > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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;
|
||||
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 > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, out_pos);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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 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 > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = 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(UNIV_PAGE_SIZE);
|
||||
case PAGE_SNAPPY_ALGORITHM: {
|
||||
size_t len = 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 > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
(int)cstatus, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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) {
|
||||
/* If error we leave the actual page as it was */
|
||||
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" rt %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
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 */
|
||||
@ -392,22 +253,11 @@ fil_compress_page(
|
||||
|
||||
/* Verify that page can be decompressed */
|
||||
{
|
||||
byte *comp_page;
|
||||
byte *uncomp_page;
|
||||
|
||||
comp_page = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE));
|
||||
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);
|
||||
|
||||
if (buf_page_is_corrupted(false, uncomp_page, 0, space)) {
|
||||
buf_page_print(uncomp_page, 0);
|
||||
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, 0, NULL));
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
@ -431,323 +281,144 @@ fil_compress_page(
|
||||
#endif
|
||||
}
|
||||
|
||||
DBUG_PRINT("compress",
|
||||
("Succeeded for space " ULINTPF
|
||||
" '%s' len " ULINTPF " out_len " ULINTPF,
|
||||
space ? space->id : 0,
|
||||
space ? space->name : "(import)",
|
||||
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();
|
||||
|
||||
/* If we do not persistently trim rest of page, we need to write it
|
||||
all */
|
||||
if (!srv_use_trim) {
|
||||
memset(out_buf+write_size,0,len-write_size);
|
||||
write_size = len;
|
||||
memset(out_buf + write_size, 0, srv_page_size - write_size);
|
||||
}
|
||||
|
||||
*out_len = write_size;
|
||||
|
||||
if (allocated) {
|
||||
/* TODO: reduce number of memcpy's */
|
||||
memcpy(buf, out_buf, len);
|
||||
} else {
|
||||
return(out_buf);
|
||||
}
|
||||
|
||||
err_exit:
|
||||
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 */
|
||||
UNIV_INTERN ulint fil_page_decompress(byte* tmp_buf, byte* buf)
|
||||
{
|
||||
int err = 0;
|
||||
ulint actual_size = 0;
|
||||
ulint compression_alg = 0;
|
||||
byte *in_buf;
|
||||
ulint ptype;
|
||||
ulint header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
|
||||
|
||||
ut_ad(buf);
|
||||
ut_ad(len);
|
||||
|
||||
ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
|
||||
|
||||
if (ptype == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
|
||||
header_len += FIL_PAGE_COMPRESSION_METHOD_SIZE;
|
||||
const unsigned ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
|
||||
ulint header_len;
|
||||
ib_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:
|
||||
return srv_page_size;
|
||||
}
|
||||
|
||||
/* Do not try to uncompressed pages that are not compressed */
|
||||
if (ptype != FIL_PAGE_PAGE_COMPRESSED &&
|
||||
ptype != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
|
||||
return;
|
||||
if (mach_read_from_4(buf + FIL_PAGE_SPACE_OR_CHKSUM)
|
||||
!= BUF_NO_CHECKSUM_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If no buffer was given, we need to allocate temporal buffer
|
||||
if (page_buf == NULL) {
|
||||
in_buf = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE));
|
||||
memset(in_buf, 0, UNIV_PAGE_SIZE);
|
||||
} else {
|
||||
in_buf = page_buf;
|
||||
}
|
||||
ulint actual_size = mach_read_from_2(buf + FIL_PAGE_DATA);
|
||||
|
||||
/* 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);
|
||||
} 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 > UNIV_PAGE_SIZE) {
|
||||
if (actual_size == 0 || actual_size > srv_page_size - header_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (compression_alg) {
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
/* Store actual payload size of the compressed data. This pointer
|
||||
points to buffer pool. */
|
||||
if (write_size) {
|
||||
*write_size = actual_size;
|
||||
}
|
||||
|
||||
DBUG_PRINT("compress",
|
||||
("Preparing for decompress for len " ULINTPF ".",
|
||||
actual_size));
|
||||
|
||||
switch(compression_alg) {
|
||||
"Unknown compression algorithm " UINT64PF,
|
||||
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) {
|
||||
|
||||
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;
|
||||
{
|
||||
uLong len = srv_page_size;
|
||||
if (Z_OK != uncompress(tmp_buf, &len,
|
||||
buf + header_len,
|
||||
uLong(actual_size))
|
||||
&& len != srv_page_size) {
|
||||
return 0;
|
||||
}
|
||||
ut_error;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
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 > 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;
|
||||
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 > 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;
|
||||
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 = UNIV_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 > 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;
|
||||
unsigned int dst_pos = srv_page_size;
|
||||
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 = UNIV_PAGE_SIZE;
|
||||
case PAGE_SNAPPY_ALGORITHM: {
|
||||
size_t 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 != 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 (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:
|
||||
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;
|
||||
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);
|
||||
}
|
||||
memcpy(buf, tmp_buf, srv_page_size);
|
||||
return actual_size;
|
||||
}
|
||||
|
@ -5177,6 +5177,11 @@ ibuf_check_bitmap_on_import(
|
||||
bitmap_page = ibuf_bitmap_get_map_page(
|
||||
space_id, page_no, zip_size, &mtr);
|
||||
|
||||
if (!bitmap_page) {
|
||||
mutex_exit(&ibuf_mutex);
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
for (i = FSP_IBUF_BITMAP_OFFSET + 1; i < page_size; i++) {
|
||||
const ulint offset = page_no + i;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
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
|
||||
@ -39,6 +39,7 @@ Created 11/5/1995 Heikki Tuuri
|
||||
#include "ut0rbt.h"
|
||||
#include "os0proc.h"
|
||||
#include "log0log.h"
|
||||
#include "my_atomic.h"
|
||||
|
||||
/** @name Modes for buf_page_get_gen */
|
||||
/* @{ */
|
||||
@ -1506,45 +1507,16 @@ buf_page_encrypt_before_write(
|
||||
buf_page_t* bpage,
|
||||
byte* src_frame);
|
||||
|
||||
/**********************************************************************
|
||||
The hook that is called after page is written to disk.
|
||||
The function releases any resources needed for encryption that was allocated
|
||||
in buf_page_encrypt_before_write */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
buf_page_encrypt_after_write(
|
||||
/*=========================*/
|
||||
buf_page_t* page); /*!< in/out: buffer page that was flushed */
|
||||
|
||||
/********************************************************************//**
|
||||
The hook that is called just before a page is read from disk.
|
||||
The function allocates memory that is used to temporarily store disk content
|
||||
before getting decrypted */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
buf_page_decrypt_before_read(
|
||||
/*=========================*/
|
||||
buf_page_t* page, /*!< in/out: buffer page read from disk */
|
||||
ulint zip_size); /*!< in: compressed page size, or 0 */
|
||||
|
||||
/********************************************************************//**
|
||||
The hook that is called just after a page is read from disk.
|
||||
The function decrypt disk content into buf_page_t and releases the
|
||||
temporary buffer that was allocated in buf_page_decrypt_before_read */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
buf_page_decrypt_after_read(
|
||||
/*========================*/
|
||||
buf_page_t* page); /*!< in/out: buffer page read from disk */
|
||||
|
||||
/** @brief The temporary memory structure.
|
||||
|
||||
NOTE! The definition appears here only for other modules of this
|
||||
directory (buf) to see it. Do not use from outside! */
|
||||
|
||||
typedef struct {
|
||||
bool reserved; /*!< true if this slot is reserved
|
||||
private:
|
||||
int32 reserved; /*!< true if this slot is reserved
|
||||
*/
|
||||
public:
|
||||
byte* crypt_buf; /*!< for encryption the data needs to be
|
||||
copied to a separate buffer before it's
|
||||
encrypted&written. this as a page can be
|
||||
@ -1555,6 +1527,21 @@ typedef struct {
|
||||
byte* out_buf; /*!< resulting buffer after
|
||||
encryption/compression. This is a
|
||||
pointer and not allocated. */
|
||||
|
||||
/** Release the slot */
|
||||
void release()
|
||||
{
|
||||
my_atomic_store32_explicit(&reserved, false,
|
||||
MY_MEMORY_ORDER_RELAXED);
|
||||
}
|
||||
|
||||
/** Acquire the slot
|
||||
@return whether the slot was acquired */
|
||||
bool acquire()
|
||||
{
|
||||
return !my_atomic_fas32_explicit(&reserved, true,
|
||||
MY_MEMORY_ORDER_RELAXED);
|
||||
}
|
||||
} buf_tmp_buffer_t;
|
||||
|
||||
/** The common buffer control block structure
|
||||
|
@ -341,9 +341,6 @@ struct fil_space_t {
|
||||
bool is_in_unflushed_spaces;
|
||||
/*!< true if this space is currently in
|
||||
unflushed_spaces */
|
||||
bool printed_compression_failure;
|
||||
/*!< true if we have already printed
|
||||
compression failure */
|
||||
fil_space_crypt_t* crypt_data;
|
||||
/*!< tablespace crypt data or NULL */
|
||||
ulint file_block_size;
|
||||
|
@ -68,7 +68,6 @@ fil_get_page_type_name(
|
||||
}
|
||||
|
||||
return "PAGE TYPE CORRUPTED";
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
|
@ -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
|
||||
@ -30,70 +30,26 @@ atomic writes information to table space.
|
||||
Created 11/12/2013 Jan Lindström jan.lindstrom@skysql.com
|
||||
***********************************************************************/
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is index page or not
|
||||
@return true if page type index page, false if not */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_index_page(
|
||||
/*===================*/
|
||||
byte *buf); /*!< in: 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 */
|
||||
UNIV_INTERN ulint fil_page_compress(const byte* buf, byte* out_buf, ulint level,
|
||||
ulint block_size, bool encrypted)
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
/****************************************************************//**
|
||||
Get the name of the compression algorithm used for page
|
||||
compression.
|
||||
@return compression algorithm name or "UNKNOWN" if not known*/
|
||||
UNIV_INLINE
|
||||
const char*
|
||||
fil_get_compression_alg_name(
|
||||
/*=========================*/
|
||||
ulint comp_alg); /*!<in: compression algorithm number */
|
||||
|
||||
/****************************************************************//**
|
||||
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 */
|
||||
|
||||
/****************************************************************//**
|
||||
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=false);
|
||||
/*!< in: true if only an error should
|
||||
be produced when decompression fails.
|
||||
By default this parameter is false. */
|
||||
|
||||
/****************************************************************//**
|
||||
Get space id from fil node
|
||||
@return space id*/
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
fil_node_get_space_id(
|
||||
/*==================*/
|
||||
fil_node_t* node); /*!< in: Node where to get space id*/
|
||||
/** 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 compressed page buffer
|
||||
@return size of the compressed data
|
||||
@retval 0 if decompression failed
|
||||
@retval srv_page_size if the page was not compressed */
|
||||
UNIV_INTERN ulint fil_page_decompress(byte* tmp_buf, byte* buf)
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
/****************************************************************//**
|
||||
Get block size from fil node
|
||||
@ -120,13 +76,4 @@ ibool
|
||||
fil_page_is_compressed_encrypted(
|
||||
/*=============================*/
|
||||
byte* buf); /*!< in: page */
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is page compressed with lzo method
|
||||
@return true if page is page compressed with lzo method*/
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_lzo_compressed(
|
||||
/*=======================*/
|
||||
byte* buf); /*!< in: page */
|
||||
#endif
|
||||
|
@ -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
|
||||
@ -49,18 +49,6 @@ fsp_flags_get_atomic_writes(
|
||||
return((atomic_writes_t)FSP_FLAGS_GET_ATOMIC_WRITES(flags));
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is index page or not
|
||||
@return true if page type index page, false if not */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_index_page(
|
||||
/*===================*/
|
||||
byte* buf) /*!< in: page */
|
||||
{
|
||||
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is page compressed
|
||||
@return true if page is page compressed, false if not */
|
||||
@ -84,59 +72,3 @@ fil_page_is_compressed_encrypted(
|
||||
{
|
||||
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Get the name of the compression algorithm used for page
|
||||
compression.
|
||||
@return compression algorithm name or "UNKNOWN" if not known*/
|
||||
UNIV_INLINE
|
||||
const char*
|
||||
fil_get_compression_alg_name(
|
||||
/*=========================*/
|
||||
ulint comp_alg) /*!<in: compression algorithm number */
|
||||
{
|
||||
switch(comp_alg) {
|
||||
case PAGE_UNCOMPRESSED:
|
||||
return ("uncompressed");
|
||||
break;
|
||||
case PAGE_ZLIB_ALGORITHM:
|
||||
return ("ZLIB");
|
||||
break;
|
||||
case PAGE_LZ4_ALGORITHM:
|
||||
return ("LZ4");
|
||||
break;
|
||||
case PAGE_LZO_ALGORITHM:
|
||||
return ("LZO");
|
||||
break;
|
||||
case PAGE_LZMA_ALGORITHM:
|
||||
return ("LZMA");
|
||||
break;
|
||||
case PAGE_BZIP2_ALGORITHM:
|
||||
return ("BZIP2");
|
||||
break;
|
||||
case PAGE_SNAPPY_ALGORITHM:
|
||||
return ("SNAPPY");
|
||||
break;
|
||||
/* No default to get compiler warning */
|
||||
}
|
||||
|
||||
return ("NULL");
|
||||
}
|
||||
|
||||
#ifndef UNIV_INNOCHECKSUM
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is page compressed with lzo method
|
||||
@return true if page is page compressed with lzo method, false if not */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_lzo_compressed(
|
||||
/*=======================*/
|
||||
byte* buf) /*!< in: page */
|
||||
{
|
||||
return((mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED &&
|
||||
mach_read_from_8(buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) == PAGE_LZO_ALGORITHM) ||
|
||||
(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED &&
|
||||
mach_read_from_2(buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE) == PAGE_LZO_ALGORITHM));
|
||||
}
|
||||
|
||||
#endif /* UNIV_INNOCHECKSUM */
|
||||
|
@ -42,6 +42,12 @@ Created 2012-02-08 by Sunny Bains.
|
||||
#include "srv0start.h"
|
||||
#include "row0quiesce.h"
|
||||
#include "fil0pagecompress.h"
|
||||
#ifdef HAVE_LZO
|
||||
#include "lzo/lzo1x.h"
|
||||
#endif
|
||||
#ifdef HAVE_SNAPPY
|
||||
#include "snappy-c.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -3365,15 +3371,30 @@ fil_iterate(
|
||||
os_offset_t offset;
|
||||
ulint n_bytes = iter.n_io_buffers * iter.page_size;
|
||||
|
||||
const ulint buf_size = srv_page_size
|
||||
#ifdef HAVE_LZO
|
||||
+ LZO1X_1_15_MEM_COMPRESS
|
||||
#elif defined HAVE_SNAPPY
|
||||
+ snappy_max_compressed_length(srv_page_size)
|
||||
#endif
|
||||
;
|
||||
byte* page_compress_buf = static_cast<byte*>(
|
||||
ut_malloc_low(buf_size, false));
|
||||
ut_ad(!srv_read_only_mode);
|
||||
|
||||
if (!page_compress_buf) {
|
||||
return DB_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* TODO: For ROW_FORMAT=COMPRESSED tables we do a lot of useless
|
||||
copying for non-index pages. Unfortunately, it is
|
||||
required by buf_zip_decompress() */
|
||||
dberr_t err = DB_SUCCESS;
|
||||
|
||||
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
|
||||
if (callback.is_interrupted()) {
|
||||
return DB_INTERRUPTED;
|
||||
err = DB_INTERRUPTED;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
byte* io_buffer = iter.io_buffer;
|
||||
@ -3404,12 +3425,13 @@ fil_iterate(
|
||||
if (!os_file_read_no_error_handling(iter.file, readptr,
|
||||
offset, n_bytes)) {
|
||||
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_read() failed");
|
||||
return DB_IO_ERROR;
|
||||
err = DB_IO_ERROR;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
bool updated = false;
|
||||
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
|
||||
const ulint size = iter.page_size;
|
||||
ulint n_pages_read = ulint(n_bytes) / size;
|
||||
block->page.offset = offset / size;
|
||||
|
||||
for (ulint i = 0; i < n_pages_read;
|
||||
@ -3438,11 +3460,11 @@ page_corrupted:
|
||||
UINT64PF " looks corrupted.",
|
||||
callback.filename(),
|
||||
ulong(offset / size), offset);
|
||||
return DB_CORRUPTION;
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
bool decrypted = false;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
byte* dst = io_buffer + (i * size);
|
||||
bool frame_changed = false;
|
||||
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
|
||||
@ -3451,6 +3473,10 @@ page_corrupted:
|
||||
== FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|
||||
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
|
||||
|
||||
if (page_compressed && block->page.zip.data) {
|
||||
goto page_corrupted;
|
||||
}
|
||||
|
||||
if (!encrypted) {
|
||||
} else if (!mach_read_from_4(
|
||||
FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
|
||||
@ -3476,7 +3502,7 @@ not_encrypted:
|
||||
iter.page_size, src, &err);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return err;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (!decrypted) {
|
||||
@ -3489,8 +3515,12 @@ not_encrypted:
|
||||
/* If the original page is page_compressed, we need
|
||||
to decompress it before adjusting further. */
|
||||
if (page_compressed) {
|
||||
fil_decompress_page(NULL, dst, ulong(size),
|
||||
NULL);
|
||||
ulint compress_length = fil_page_decompress(
|
||||
page_compress_buf, dst);
|
||||
ut_ad(compress_length != srv_page_size);
|
||||
if (compress_length == 0) {
|
||||
goto page_corrupted;
|
||||
}
|
||||
updated = true;
|
||||
} else if (buf_page_is_corrupted(
|
||||
false,
|
||||
@ -3501,7 +3531,7 @@ not_encrypted:
|
||||
}
|
||||
|
||||
if ((err = callback(block)) != DB_SUCCESS) {
|
||||
return err;
|
||||
goto func_exit;
|
||||
} else if (!updated) {
|
||||
updated = buf_block_get_state(block)
|
||||
== BUF_BLOCK_FILE_PAGE;
|
||||
@ -3551,19 +3581,17 @@ not_encrypted:
|
||||
src = io_buffer + (i * size);
|
||||
|
||||
if (page_compressed) {
|
||||
ulint len = 0;
|
||||
|
||||
fil_compress_page(
|
||||
NULL,
|
||||
src,
|
||||
NULL,
|
||||
size,
|
||||
0,/* FIXME: compression level */
|
||||
512,/* FIXME: use proper block size */
|
||||
encrypted,
|
||||
&len);
|
||||
|
||||
updated = true;
|
||||
if (fil_page_compress(
|
||||
src,
|
||||
page_compress_buf,
|
||||
0,/* FIXME: compression level */
|
||||
512,/* FIXME: proper block size */
|
||||
encrypted)) {
|
||||
/* FIXME: remove memcpy() */
|
||||
memcpy(src, page_compress_buf,
|
||||
srv_page_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* If tablespace is encrypted, encrypt page before we
|
||||
@ -3600,11 +3628,14 @@ not_encrypted:
|
||||
offset, (ulint) n_bytes)) {
|
||||
|
||||
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
|
||||
return DB_IO_ERROR;
|
||||
err = DB_IO_ERROR;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
return DB_SUCCESS;
|
||||
func_exit:
|
||||
ut_free(page_compress_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
|
@ -77,15 +77,6 @@ Created 11/5/1995 Heikki Tuuri
|
||||
#include "snappy-c.h"
|
||||
#endif
|
||||
|
||||
/** Decrypt a page.
|
||||
@param[in,out] bpage Page control block
|
||||
@param[in,out] space tablespace
|
||||
@return whether the operation was successful */
|
||||
static
|
||||
bool
|
||||
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
|
||||
/********************************************************************//**
|
||||
Mark a table with the specified space pointed by bpage->space corrupted.
|
||||
Also remove the bpage from LRU list.
|
||||
@ -390,6 +381,143 @@ on the io_type */
|
||||
? (counter##_READ) \
|
||||
: (counter##_WRITTEN))
|
||||
|
||||
|
||||
/** Reserve a buffer slot for encryption, decryption or page compression.
|
||||
@param[in,out] buf_pool buffer pool
|
||||
@return reserved buffer slot */
|
||||
static buf_tmp_buffer_t* buf_pool_reserve_tmp_slot(buf_pool_t* buf_pool)
|
||||
{
|
||||
for (ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
|
||||
buf_tmp_buffer_t* slot = &buf_pool->tmp_arr->slots[i];
|
||||
if (slot->acquire()) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume that free slot is found */
|
||||
ut_error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Reserve a buffer for encryption, decryption or decompression.
|
||||
@param[in,out] slot reserved slot */
|
||||
static void buf_tmp_reserve_crypt_buf(buf_tmp_buffer_t* slot)
|
||||
{
|
||||
if (!slot->crypt_buf) {
|
||||
slot->crypt_buf = static_cast<byte*>(
|
||||
aligned_malloc(srv_page_size, srv_page_size));
|
||||
}
|
||||
}
|
||||
|
||||
/** Reserve a buffer for compression.
|
||||
@param[in,out] slot reserved slot */
|
||||
static void buf_tmp_reserve_compression_buf(buf_tmp_buffer_t* slot)
|
||||
{
|
||||
if (!slot->comp_buf) {
|
||||
/* Both snappy and lzo compression methods require that
|
||||
output buffer used for compression is bigger than input
|
||||
buffer. Increase the allocated buffer size accordingly. */
|
||||
ulint size = srv_page_size;
|
||||
#ifdef HAVE_LZO
|
||||
size += LZO1X_1_15_MEM_COMPRESS;
|
||||
#elif defined HAVE_SNAPPY
|
||||
size = snappy_max_compressed_length(size);
|
||||
#endif
|
||||
slot->comp_buf = static_cast<byte*>(
|
||||
aligned_malloc(size, srv_page_size));
|
||||
}
|
||||
}
|
||||
|
||||
/** Decrypt a page.
|
||||
@param[in,out] bpage Page control block
|
||||
@param[in,out] space tablespace
|
||||
@return whether the operation was successful */
|
||||
static bool buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
|
||||
{
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
ut_ad(space->id == bpage->space);
|
||||
|
||||
byte* dst_frame = bpage->zip.data ? bpage->zip.data :
|
||||
((buf_block_t*) bpage)->frame;
|
||||
bool page_compressed = fil_page_is_compressed(dst_frame);
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
|
||||
if (bpage->offset == 0) {
|
||||
/* File header pages are not encrypted/compressed */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Page is encrypted if encryption information is found from
|
||||
tablespace and page contains used key_version. This is true
|
||||
also for pages first compressed and then encrypted. */
|
||||
|
||||
buf_tmp_buffer_t* slot;
|
||||
|
||||
if (page_compressed) {
|
||||
/* the page we read is unencrypted */
|
||||
/* Find free slot from temporary memory array */
|
||||
decompress:
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool);
|
||||
/* For decompression, use crypt_buf. */
|
||||
buf_tmp_reserve_crypt_buf(slot);
|
||||
decompress_with_slot:
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
bpage->write_size = fil_page_decompress(slot->crypt_buf,
|
||||
dst_frame);
|
||||
slot->release();
|
||||
|
||||
ut_ad(!bpage->write_size || fil_page_type_validate(dst_frame));
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
return bpage->write_size != 0;
|
||||
}
|
||||
|
||||
if (space->crypt_data
|
||||
&& mach_read_from_4(FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
|
||||
+ dst_frame)) {
|
||||
/* Verify encryption checksum before we even try to
|
||||
decrypt. */
|
||||
if (!fil_space_verify_crypt_checksum(
|
||||
dst_frame, buf_page_get_zip_size(bpage), NULL,
|
||||
bpage->offset)) {
|
||||
decrypt_failed:
|
||||
/* Mark page encrypted in case it should be. */
|
||||
if (space->crypt_data->type
|
||||
!= CRYPT_SCHEME_UNENCRYPTED) {
|
||||
bpage->encrypted = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find free slot from temporary memory array */
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool);
|
||||
buf_tmp_reserve_crypt_buf(slot);
|
||||
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
/* decrypt using crypt_buf to dst_frame */
|
||||
if (!fil_space_decrypt(space, slot->crypt_buf,
|
||||
dst_frame, &bpage->encrypted)) {
|
||||
slot->release();
|
||||
goto decrypt_failed;
|
||||
}
|
||||
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
if (fil_page_is_compressed_encrypted(dst_frame)) {
|
||||
goto decompress_with_slot;
|
||||
}
|
||||
|
||||
slot->release();
|
||||
} else if (fil_page_is_compressed_encrypted(dst_frame)) {
|
||||
goto decompress;
|
||||
}
|
||||
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Gets the smallest oldest_modification lsn for any page in the pool. Returns
|
||||
zero if all modified pages have been flushed to disk.
|
||||
@ -4730,7 +4858,6 @@ buf_page_io_complete(buf_page_t* bpage)
|
||||
const ibool uncompressed = (buf_page_get_state(bpage)
|
||||
== BUF_BLOCK_FILE_PAGE);
|
||||
bool have_LRU_mutex = false;
|
||||
byte* frame = NULL;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
|
||||
ut_a(buf_page_in_file(bpage));
|
||||
@ -4748,19 +4875,18 @@ buf_page_io_complete(buf_page_t* bpage)
|
||||
ulint read_page_no = 0;
|
||||
ulint read_space_id = 0;
|
||||
uint key_version = 0;
|
||||
|
||||
ut_ad(bpage->zip.data || ((buf_block_t*)bpage)->frame);
|
||||
byte* frame = bpage->zip.data
|
||||
? bpage->zip.data
|
||||
: reinterpret_cast<buf_block_t*>(bpage)->frame;
|
||||
ut_ad(frame);
|
||||
fil_space_t* space = fil_space_acquire_for_io(bpage->space);
|
||||
if (!space) {
|
||||
return(DB_TABLESPACE_DELETED);
|
||||
}
|
||||
|
||||
buf_page_decrypt_after_read(bpage, space);
|
||||
|
||||
if (buf_page_get_zip_size(bpage)) {
|
||||
frame = bpage->zip.data;
|
||||
} else {
|
||||
frame = ((buf_block_t*) bpage)->frame;
|
||||
if (!buf_page_decrypt_after_read(bpage, space)) {
|
||||
err = DB_DECRYPTION_FAILED;
|
||||
goto database_corrupted;
|
||||
}
|
||||
|
||||
if (buf_page_get_zip_size(bpage)) {
|
||||
@ -4941,7 +5067,7 @@ database_corrupted:
|
||||
/* io_type == BUF_IO_WRITE */
|
||||
if (bpage->slot) {
|
||||
/* Mark slot free */
|
||||
bpage->slot->reserved = false;
|
||||
bpage->slot->release();
|
||||
bpage->slot = NULL;
|
||||
}
|
||||
}
|
||||
@ -6240,66 +6366,6 @@ buf_pool_mutex_exit(
|
||||
mutex_exit(&buf_pool->LRU_list_mutex);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Reserve unused slot from temporary memory array and allocate necessary
|
||||
temporary memory if not yet allocated.
|
||||
@return reserved slot */
|
||||
UNIV_INTERN
|
||||
buf_tmp_buffer_t*
|
||||
buf_pool_reserve_tmp_slot(
|
||||
/*======================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool where to
|
||||
reserve */
|
||||
bool compressed) /*!< in: is file space compressed */
|
||||
{
|
||||
buf_tmp_buffer_t *free_slot=NULL;
|
||||
|
||||
/* Array is protected by buf_pool mutex */
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
|
||||
for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
|
||||
buf_tmp_buffer_t *slot = &buf_pool->tmp_arr->slots[i];
|
||||
|
||||
if(slot->reserved == false) {
|
||||
free_slot = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume that free slot is found */
|
||||
ut_a(free_slot != NULL);
|
||||
free_slot->reserved = true;
|
||||
/* Now that we have reserved this slot we can release
|
||||
buf_pool mutex */
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
|
||||
/* Allocate temporary memory for encryption/decryption */
|
||||
if (free_slot->crypt_buf == NULL) {
|
||||
free_slot->crypt_buf = static_cast<byte*>(aligned_malloc(UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
|
||||
memset(free_slot->crypt_buf, 0, UNIV_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* For page compressed tables allocate temporary memory for
|
||||
compression/decompression */
|
||||
if (compressed && free_slot->comp_buf == NULL) {
|
||||
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
|
||||
size = snappy_max_compressed_length(size);
|
||||
#endif
|
||||
#if HAVE_LZO
|
||||
size += LZO1X_1_15_MEM_COMPRESS;
|
||||
#endif
|
||||
free_slot->comp_buf = static_cast<byte*>(aligned_malloc(size, UNIV_PAGE_SIZE));
|
||||
memset(free_slot->comp_buf, 0, size);
|
||||
}
|
||||
|
||||
return (free_slot);
|
||||
}
|
||||
|
||||
/** Encryption and page_compression hook that is called just before
|
||||
a page is written to disk.
|
||||
@param[in,out] space tablespace
|
||||
@ -6349,16 +6415,18 @@ buf_page_encrypt_before_write(
|
||||
}
|
||||
|
||||
ulint zip_size = buf_page_get_zip_size(bpage);
|
||||
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
|
||||
ut_ad(!zip_size || !page_compressed);
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
/* Find free slot from temporary memory array */
|
||||
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool);
|
||||
slot->out_buf = NULL;
|
||||
bpage->slot = slot;
|
||||
|
||||
buf_tmp_reserve_crypt_buf(slot);
|
||||
byte *dst_frame = slot->crypt_buf;
|
||||
|
||||
if (!page_compressed) {
|
||||
not_compressed:
|
||||
/* Encrypt page content */
|
||||
byte* tmp = fil_space_encrypt(space,
|
||||
bpage->offset,
|
||||
@ -6366,32 +6434,28 @@ buf_page_encrypt_before_write(
|
||||
src_frame,
|
||||
dst_frame);
|
||||
|
||||
bpage->real_size = page_size;
|
||||
bpage->real_size = UNIV_PAGE_SIZE;
|
||||
slot->out_buf = dst_frame = tmp;
|
||||
|
||||
ut_d(fil_page_type_validate(tmp));
|
||||
} else {
|
||||
/* First we compress the page content */
|
||||
ulint out_len = 0;
|
||||
|
||||
byte *tmp = fil_compress_page(
|
||||
space,
|
||||
(byte *)src_frame,
|
||||
slot->comp_buf,
|
||||
page_size,
|
||||
buf_tmp_reserve_compression_buf(slot);
|
||||
byte* tmp = slot->comp_buf;
|
||||
ulint out_len = fil_page_compress(
|
||||
src_frame, tmp,
|
||||
fsp_flags_get_page_compression_level(space->flags),
|
||||
fil_space_get_block_size(space, bpage->offset),
|
||||
encrypted,
|
||||
&out_len);
|
||||
encrypted);
|
||||
if (!out_len) {
|
||||
goto not_compressed;
|
||||
}
|
||||
|
||||
bpage->real_size = out_len;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(tmp);
|
||||
#endif
|
||||
|
||||
if(encrypted) {
|
||||
ut_d(fil_page_type_validate(tmp));
|
||||
|
||||
if (encrypted) {
|
||||
/* And then we encrypt the page content */
|
||||
tmp = fil_space_encrypt(space,
|
||||
bpage->offset,
|
||||
@ -6403,130 +6467,8 @@ buf_page_encrypt_before_write(
|
||||
slot->out_buf = dst_frame = tmp;
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
|
||||
// return dst_frame which will be written
|
||||
return dst_frame;
|
||||
}
|
||||
|
||||
/** Decrypt a page.
|
||||
@param[in,out] bpage Page control block
|
||||
@param[in,out] space tablespace
|
||||
@return whether the operation was successful */
|
||||
static
|
||||
bool
|
||||
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
|
||||
{
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
ut_ad(space->id == bpage->space);
|
||||
|
||||
ulint zip_size = buf_page_get_zip_size(bpage);
|
||||
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
|
||||
|
||||
byte* dst_frame = (zip_size) ? bpage->zip.data :
|
||||
((buf_block_t*) bpage)->frame;
|
||||
unsigned key_version =
|
||||
mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
|
||||
bool page_compressed = fil_page_is_compressed(dst_frame);
|
||||
bool page_compressed_encrypted = fil_page_is_compressed_encrypted(dst_frame);
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
bool success = true;
|
||||
|
||||
if (bpage->offset == 0) {
|
||||
/* File header pages are not encrypted/compressed */
|
||||
return (true);
|
||||
}
|
||||
|
||||
/* Page is encrypted if encryption information is found from
|
||||
tablespace and page contains used key_version. This is true
|
||||
also for pages first compressed and then encrypted. */
|
||||
if (!space->crypt_data) {
|
||||
key_version = 0;
|
||||
}
|
||||
|
||||
if (page_compressed) {
|
||||
/* the page we read is unencrypted */
|
||||
/* Find free slot from temporary memory array */
|
||||
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
|
||||
/* decompress using comp_buf to dst_frame */
|
||||
fil_decompress_page(slot->comp_buf,
|
||||
dst_frame,
|
||||
ulong(size),
|
||||
&bpage->write_size);
|
||||
|
||||
/* Mark this slot as free */
|
||||
slot->reserved = false;
|
||||
key_version = 0;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
} else {
|
||||
buf_tmp_buffer_t* slot = NULL;
|
||||
|
||||
if (key_version) {
|
||||
/* Verify encryption checksum before we even try to
|
||||
decrypt. */
|
||||
if (!fil_space_verify_crypt_checksum(dst_frame,
|
||||
zip_size, NULL, bpage->offset)) {
|
||||
|
||||
/* Mark page encrypted in case it should
|
||||
be. */
|
||||
if (space->crypt_data->type
|
||||
!= CRYPT_SCHEME_UNENCRYPTED) {
|
||||
bpage->encrypted = true;
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
/* Find free slot from temporary memory array */
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
|
||||
/* decrypt using crypt_buf to dst_frame */
|
||||
if (!fil_space_decrypt(space, slot->crypt_buf,
|
||||
dst_frame, &bpage->encrypted)) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (page_compressed_encrypted && success) {
|
||||
if (!slot) {
|
||||
slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
fil_page_type_validate(dst_frame);
|
||||
#endif
|
||||
/* decompress using comp_buf to dst_frame */
|
||||
fil_decompress_page(slot->comp_buf,
|
||||
dst_frame,
|
||||
ulong(size),
|
||||
&bpage->write_size);
|
||||
ut_d(fil_page_type_validate(dst_frame));
|
||||
}
|
||||
|
||||
/* Mark this slot as free */
|
||||
if (slot) {
|
||||
slot->reserved = false;
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(space->n_pending_ios > 0);
|
||||
return (success);
|
||||
}
|
||||
|
@ -510,10 +510,11 @@ buf_dblwr_process()
|
||||
"Restoring possible half-written data pages "
|
||||
"from the doublewrite buffer...");
|
||||
|
||||
unaligned_read_buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
|
||||
unaligned_read_buf = static_cast<byte*>(ut_malloc(3 * UNIV_PAGE_SIZE));
|
||||
|
||||
read_buf = static_cast<byte*>(
|
||||
ut_align(unaligned_read_buf, UNIV_PAGE_SIZE));
|
||||
byte* const buf = read_buf + UNIV_PAGE_SIZE;
|
||||
|
||||
for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
|
||||
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
|
||||
@ -562,24 +563,26 @@ buf_dblwr_process()
|
||||
ignore this page (there should be redo log
|
||||
records to initialize it). */
|
||||
} else {
|
||||
if (fil_page_is_compressed_encrypted(read_buf) ||
|
||||
fil_page_is_compressed(read_buf)) {
|
||||
/* Decompress the page before
|
||||
validating the checksum. */
|
||||
fil_decompress_page(
|
||||
NULL, read_buf, srv_page_size,
|
||||
NULL, true);
|
||||
/* Decompress the page before
|
||||
validating the checksum. */
|
||||
ulint decomp = fil_page_decompress(buf, read_buf);
|
||||
if (!decomp) {
|
||||
goto bad;
|
||||
}
|
||||
if (!decomp || (decomp != srv_page_size && zip_size)) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (fil_space_verify_crypt_checksum(
|
||||
read_buf, zip_size, NULL, page_no)
|
||||
|| !buf_page_is_corrupted(
|
||||
true, read_buf, zip_size, space())) {
|
||||
read_buf, zip_size, NULL, page_no)
|
||||
|| !buf_page_is_corrupted(
|
||||
true, read_buf, zip_size, space())) {
|
||||
/* The page is good; there is no need
|
||||
to consult the doublewrite buffer. */
|
||||
continue;
|
||||
}
|
||||
|
||||
bad:
|
||||
/* We intentionally skip this message for
|
||||
is_all_zero pages. */
|
||||
ib_logf(IB_LOG_LEVEL_INFO,
|
||||
@ -588,18 +591,15 @@ buf_dblwr_process()
|
||||
space_id, page_no);
|
||||
}
|
||||
|
||||
/* Next, validate the doublewrite page. */
|
||||
if (fil_page_is_compressed_encrypted(page) ||
|
||||
fil_page_is_compressed(page)) {
|
||||
/* Decompress the page before
|
||||
validating the checksum. */
|
||||
fil_decompress_page(
|
||||
NULL, page, srv_page_size, NULL, true);
|
||||
ulint decomp = fil_page_decompress(buf, page);
|
||||
if (!decomp || (decomp != srv_page_size && zip_size)) {
|
||||
goto bad_doublewrite;
|
||||
}
|
||||
|
||||
if (!fil_space_verify_crypt_checksum(page, zip_size, NULL, page_no)
|
||||
if (!fil_space_verify_crypt_checksum(page, zip_size, NULL,
|
||||
page_no)
|
||||
&& buf_page_is_corrupted(true, page, zip_size, space)) {
|
||||
if (!is_all_zero) {
|
||||
bad_doublewrite:
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"A doublewrite copy of page "
|
||||
ULINTPF ":" ULINTPF " is corrupted.",
|
||||
|
@ -708,60 +708,39 @@ fil_space_encrypt(
|
||||
#ifdef UNIV_DEBUG
|
||||
if (tmp) {
|
||||
/* Verify that encrypted buffer is not corrupted */
|
||||
byte* tmp_mem = (byte *)malloc(UNIV_PAGE_SIZE);
|
||||
dberr_t err = DB_SUCCESS;
|
||||
byte* src = src_frame;
|
||||
bool page_compressed_encrypted = (mach_read_from_2(tmp+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
|
||||
byte* comp_mem = NULL;
|
||||
byte* uncomp_mem = NULL;
|
||||
byte uncomp_mem[UNIV_PAGE_SIZE_MAX];
|
||||
byte tmp_mem[UNIV_PAGE_SIZE_MAX];
|
||||
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
|
||||
|
||||
if (page_compressed_encrypted) {
|
||||
comp_mem = (byte *)malloc(UNIV_PAGE_SIZE);
|
||||
uncomp_mem = (byte *)malloc(UNIV_PAGE_SIZE);
|
||||
memcpy(comp_mem, src_frame, UNIV_PAGE_SIZE);
|
||||
fil_decompress_page(uncomp_mem, comp_mem,
|
||||
srv_page_size, NULL);
|
||||
src = uncomp_mem;
|
||||
memcpy(uncomp_mem, src, srv_page_size);
|
||||
ulint unzipped1 = fil_page_decompress(
|
||||
tmp_mem, uncomp_mem);
|
||||
ut_ad(unzipped1);
|
||||
if (unzipped1 != srv_page_size) {
|
||||
src = uncomp_mem;
|
||||
}
|
||||
}
|
||||
|
||||
bool corrupted1 = buf_page_is_corrupted(true, src, zip_size, space);
|
||||
bool ok = fil_space_decrypt(crypt_data, tmp_mem, size, tmp, &err);
|
||||
ut_ad(!buf_page_is_corrupted(true, src, zip_size, space));
|
||||
ut_ad(fil_space_decrypt(crypt_data, tmp_mem, size, tmp, &err));
|
||||
ut_ad(err == DB_SUCCESS);
|
||||
|
||||
/* Need to decompress the page if it was also compressed */
|
||||
if (page_compressed_encrypted) {
|
||||
memcpy(comp_mem, tmp_mem, UNIV_PAGE_SIZE);
|
||||
fil_decompress_page(tmp_mem, comp_mem,
|
||||
srv_page_size, NULL);
|
||||
byte buf[UNIV_PAGE_SIZE_MAX];
|
||||
memcpy(buf, tmp_mem, srv_page_size);
|
||||
ulint unzipped2 = fil_page_decompress(tmp_mem, buf);
|
||||
ut_ad(unzipped2);
|
||||
}
|
||||
|
||||
bool corrupted = buf_page_is_corrupted(true, tmp_mem, zip_size, space);
|
||||
memcpy(tmp_mem+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, src+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8);
|
||||
bool different = memcmp(src, tmp_mem, size);
|
||||
|
||||
if (!ok || corrupted || corrupted1 || err != DB_SUCCESS || different) {
|
||||
fprintf(stderr, "ok %d corrupted %d corrupted1 %d err %d different %d\n",
|
||||
ok , corrupted, corrupted1, err, different);
|
||||
fprintf(stderr, "src_frame\n");
|
||||
buf_page_print(src_frame, zip_size);
|
||||
fprintf(stderr, "encrypted_frame\n");
|
||||
buf_page_print(tmp, zip_size);
|
||||
fprintf(stderr, "decrypted_frame\n");
|
||||
buf_page_print(tmp_mem, zip_size);
|
||||
ut_ad(0);
|
||||
}
|
||||
|
||||
free(tmp_mem);
|
||||
|
||||
if (comp_mem) {
|
||||
free(comp_mem);
|
||||
}
|
||||
|
||||
if (uncomp_mem) {
|
||||
free(uncomp_mem);
|
||||
}
|
||||
memcpy(tmp_mem + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION,
|
||||
src + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8);
|
||||
ut_ad(!memcmp(src, tmp_mem, size));
|
||||
}
|
||||
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
return tmp;
|
||||
|
@ -351,19 +351,6 @@ fil_space_get_by_id(
|
||||
return(space);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Get space id from fil node */
|
||||
ulint
|
||||
fil_node_get_space_id(
|
||||
/*==================*/
|
||||
fil_node_t* node) /*!< in: Compressed node*/
|
||||
{
|
||||
ut_ad(node);
|
||||
ut_ad(node->space);
|
||||
|
||||
return (node->space->id);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Returns the table space by a given name, NULL if not found. */
|
||||
fil_space_t*
|
||||
|
@ -80,73 +80,26 @@ static ulint srv_data_read, srv_data_written;
|
||||
#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 */
|
||||
UNIV_INTERN ulint fil_page_compress(const byte* buf, byte* out_buf, ulint level,
|
||||
ulint block_size, bool encrypted)
|
||||
{
|
||||
int err = Z_OK;
|
||||
int comp_level = level;
|
||||
int comp_level = int(level);
|
||||
ulint header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
|
||||
ulint write_size = 0;
|
||||
#if 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 = 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
|
||||
if (comp_method == PAGE_LZO_ALGORITHM) {
|
||||
size += LZO1X_1_15_MEM_COMPRESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
out_buf = static_cast<byte *>(ut_malloc(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)) {
|
||||
@ -154,8 +107,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
|
||||
@ -164,204 +116,113 @@ fil_compress_page(
|
||||
comp_level = page_zip_level;
|
||||
}
|
||||
|
||||
DBUG_PRINT("compress",
|
||||
("Preparing for space " ULINTPF " '%s' len " ULINTPF,
|
||||
space ? space->id : 0,
|
||||
space ? space->name : "(import)",
|
||||
len));
|
||||
ulint write_size = srv_page_size - header_len;
|
||||
|
||||
write_size = UNIV_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
|
||||
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
|
||||
|
||||
#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) {
|
||||
/* 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_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
#ifndef UNIV_PAGECOMPRESS_DEBUG
|
||||
}
|
||||
#endif
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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+UNIV_PAGE_SIZE);
|
||||
case PAGE_LZO_ALGORITHM: {
|
||||
lzo_uint len = write_size;
|
||||
|
||||
write_size = write_size_lzo;
|
||||
|
||||
if (err != LZO_E_OK || write_size > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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;
|
||||
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 > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, out_pos);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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 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 > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = 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(UNIV_PAGE_SIZE);
|
||||
case PAGE_SNAPPY_ALGORITHM: {
|
||||
size_t len = 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 > UNIV_PAGE_SIZE-header_len) {
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" err %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
(int)cstatus, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
goto err_exit;
|
||||
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) {
|
||||
/* If error we leave the actual page as it was */
|
||||
|
||||
if (space && !space->printed_compression_failure) {
|
||||
space->printed_compression_failure = true;
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Compression failed for space " ULINTPF
|
||||
" name %s len " ULINTPF
|
||||
" rt %d write_size " ULINTPF ".",
|
||||
space->id, space->name, len,
|
||||
err, write_size);
|
||||
}
|
||||
|
||||
srv_stats.pages_page_compression_error.inc();
|
||||
*out_len = len;
|
||||
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 */
|
||||
@ -392,22 +253,11 @@ fil_compress_page(
|
||||
|
||||
/* Verify that page can be decompressed */
|
||||
{
|
||||
byte *comp_page;
|
||||
byte *uncomp_page;
|
||||
|
||||
comp_page = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE));
|
||||
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);
|
||||
|
||||
if (buf_page_is_corrupted(false, uncomp_page, 0, space)) {
|
||||
buf_page_print(uncomp_page, 0);
|
||||
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, 0, NULL));
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
@ -431,323 +281,144 @@ fil_compress_page(
|
||||
#endif
|
||||
}
|
||||
|
||||
DBUG_PRINT("compress",
|
||||
("Succeeded for space " ULINTPF
|
||||
" '%s' len " ULINTPF " out_len " ULINTPF,
|
||||
space ? space->id : 0,
|
||||
space ? space->name : "(import)",
|
||||
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();
|
||||
|
||||
/* If we do not persistently trim rest of page, we need to write it
|
||||
all */
|
||||
if (!srv_use_trim) {
|
||||
memset(out_buf+write_size,0,len-write_size);
|
||||
write_size = len;
|
||||
memset(out_buf + write_size, 0, srv_page_size - write_size);
|
||||
}
|
||||
|
||||
*out_len = write_size;
|
||||
|
||||
if (allocated) {
|
||||
/* TODO: reduce number of memcpy's */
|
||||
memcpy(buf, out_buf, len);
|
||||
} else {
|
||||
return(out_buf);
|
||||
}
|
||||
|
||||
err_exit:
|
||||
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 */
|
||||
UNIV_INTERN ulint fil_page_decompress(byte* tmp_buf, byte* buf)
|
||||
{
|
||||
int err = 0;
|
||||
ulint actual_size = 0;
|
||||
ulint compression_alg = 0;
|
||||
byte *in_buf;
|
||||
ulint ptype;
|
||||
ulint header_len = FIL_PAGE_DATA + FIL_PAGE_COMPRESSED_SIZE;
|
||||
|
||||
ut_ad(buf);
|
||||
ut_ad(len);
|
||||
|
||||
ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
|
||||
|
||||
if (ptype == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
|
||||
header_len += FIL_PAGE_COMPRESSION_METHOD_SIZE;
|
||||
const unsigned ptype = mach_read_from_2(buf+FIL_PAGE_TYPE);
|
||||
ulint header_len;
|
||||
ib_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:
|
||||
return srv_page_size;
|
||||
}
|
||||
|
||||
/* Do not try to uncompressed pages that are not compressed */
|
||||
if (ptype != FIL_PAGE_PAGE_COMPRESSED &&
|
||||
ptype != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
|
||||
return;
|
||||
if (mach_read_from_4(buf + FIL_PAGE_SPACE_OR_CHKSUM)
|
||||
!= BUF_NO_CHECKSUM_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If no buffer was given, we need to allocate temporal buffer
|
||||
if (page_buf == NULL) {
|
||||
in_buf = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE));
|
||||
memset(in_buf, 0, UNIV_PAGE_SIZE);
|
||||
} else {
|
||||
in_buf = page_buf;
|
||||
}
|
||||
ulint actual_size = mach_read_from_2(buf + FIL_PAGE_DATA);
|
||||
|
||||
/* 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);
|
||||
} 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 > UNIV_PAGE_SIZE) {
|
||||
if (actual_size == 0 || actual_size > srv_page_size - header_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (compression_alg) {
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
/* Store actual payload size of the compressed data. This pointer
|
||||
points to buffer pool. */
|
||||
if (write_size) {
|
||||
*write_size = actual_size;
|
||||
}
|
||||
|
||||
DBUG_PRINT("compress",
|
||||
("Preparing for decompress for len " ULINTPF ".",
|
||||
actual_size));
|
||||
|
||||
switch(compression_alg) {
|
||||
"Unknown compression algorithm " UINT64PF,
|
||||
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) {
|
||||
|
||||
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;
|
||||
{
|
||||
uLong len = srv_page_size;
|
||||
if (Z_OK != uncompress(tmp_buf, &len,
|
||||
buf + header_len,
|
||||
uLong(actual_size))
|
||||
&& len != srv_page_size) {
|
||||
return 0;
|
||||
}
|
||||
ut_error;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
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 > 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;
|
||||
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 > 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;
|
||||
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 = UNIV_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 > 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;
|
||||
unsigned int dst_pos = srv_page_size;
|
||||
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 = UNIV_PAGE_SIZE;
|
||||
case PAGE_SNAPPY_ALGORITHM: {
|
||||
size_t 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 != 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 (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:
|
||||
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;
|
||||
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);
|
||||
}
|
||||
memcpy(buf, tmp_buf, srv_page_size);
|
||||
return actual_size;
|
||||
}
|
||||
|
@ -5218,6 +5218,10 @@ ibuf_check_bitmap_on_import(
|
||||
|
||||
bitmap_page = ibuf_bitmap_get_map_page(
|
||||
space_id, page_no, zip_size, &mtr);
|
||||
if (!bitmap_page) {
|
||||
mutex_exit(&ibuf_mutex);
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
for (i = FSP_IBUF_BITMAP_OFFSET + 1; i < page_size; i++) {
|
||||
const ulint offset = page_no + i;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
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
|
||||
@ -38,6 +38,7 @@ Created 11/5/1995 Heikki Tuuri
|
||||
#include "ut0rbt.h"
|
||||
#include "os0proc.h"
|
||||
#include "log0log.h"
|
||||
#include "my_atomic.h"
|
||||
|
||||
/** @name Modes for buf_page_get_gen */
|
||||
/* @{ */
|
||||
@ -1528,45 +1529,16 @@ buf_page_encrypt_before_write(
|
||||
buf_page_t* bpage,
|
||||
byte* src_frame);
|
||||
|
||||
/**********************************************************************
|
||||
The hook that is called after page is written to disk.
|
||||
The function releases any resources needed for encryption that was allocated
|
||||
in buf_page_encrypt_before_write */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
buf_page_encrypt_after_write(
|
||||
/*=========================*/
|
||||
buf_page_t* page); /*!< in/out: buffer page that was flushed */
|
||||
|
||||
/********************************************************************//**
|
||||
The hook that is called just before a page is read from disk.
|
||||
The function allocates memory that is used to temporarily store disk content
|
||||
before getting decrypted */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
buf_page_decrypt_before_read(
|
||||
/*=========================*/
|
||||
buf_page_t* page, /*!< in/out: buffer page read from disk */
|
||||
ulint zip_size); /*!< in: compressed page size, or 0 */
|
||||
|
||||
/********************************************************************//**
|
||||
The hook that is called just after a page is read from disk.
|
||||
The function decrypt disk content into buf_page_t and releases the
|
||||
temporary buffer that was allocated in buf_page_decrypt_before_read */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
buf_page_decrypt_after_read(
|
||||
/*========================*/
|
||||
buf_page_t* page); /*!< in/out: buffer page read from disk */
|
||||
|
||||
/** @brief The temporary memory structure.
|
||||
|
||||
NOTE! The definition appears here only for other modules of this
|
||||
directory (buf) to see it. Do not use from outside! */
|
||||
|
||||
typedef struct {
|
||||
bool reserved; /*!< true if this slot is reserved
|
||||
private:
|
||||
int32 reserved; /*!< true if this slot is reserved
|
||||
*/
|
||||
public:
|
||||
byte* crypt_buf; /*!< for encryption the data needs to be
|
||||
copied to a separate buffer before it's
|
||||
encrypted&written. this as a page can be
|
||||
@ -1577,6 +1549,21 @@ typedef struct {
|
||||
byte* out_buf; /*!< resulting buffer after
|
||||
encryption/compression. This is a
|
||||
pointer and not allocated. */
|
||||
|
||||
/** Release the slot */
|
||||
void release()
|
||||
{
|
||||
my_atomic_store32_explicit(&reserved, false,
|
||||
MY_MEMORY_ORDER_RELAXED);
|
||||
}
|
||||
|
||||
/** Acquire the slot
|
||||
@return whether the slot was acquired */
|
||||
bool acquire()
|
||||
{
|
||||
return !my_atomic_fas32_explicit(&reserved, true,
|
||||
MY_MEMORY_ORDER_RELAXED);
|
||||
}
|
||||
} buf_tmp_buffer_t;
|
||||
|
||||
/** The common buffer control block structure
|
||||
|
@ -340,9 +340,6 @@ struct fil_space_t {
|
||||
corrupted page. */
|
||||
bool is_corrupt;
|
||||
/*!< true if tablespace corrupted */
|
||||
bool printed_compression_failure;
|
||||
/*!< true if we have already printed
|
||||
compression failure */
|
||||
fil_space_crypt_t* crypt_data;
|
||||
/*!< tablespace crypt data or NULL */
|
||||
ulint file_block_size;
|
||||
|
@ -68,7 +68,6 @@ fil_get_page_type_name(
|
||||
}
|
||||
|
||||
return "PAGE TYPE CORRUPTED";
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
|
@ -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
|
||||
@ -30,70 +30,26 @@ atomic writes information to table space.
|
||||
Created 11/12/2013 Jan Lindström jan.lindstrom@skysql.com
|
||||
***********************************************************************/
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is index page or not
|
||||
@return true if page type index page, false if not */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_index_page(
|
||||
/*===================*/
|
||||
byte *buf); /*!< in: 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 */
|
||||
UNIV_INTERN ulint fil_page_compress(const byte* buf, byte* out_buf, ulint level,
|
||||
ulint block_size, bool encrypted)
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
/****************************************************************//**
|
||||
Get the name of the compression algorithm used for page
|
||||
compression.
|
||||
@return compression algorithm name or "UNKNOWN" if not known*/
|
||||
UNIV_INLINE
|
||||
const char*
|
||||
fil_get_compression_alg_name(
|
||||
/*=========================*/
|
||||
ulint comp_alg); /*!<in: compression algorithm number */
|
||||
|
||||
/****************************************************************//**
|
||||
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 */
|
||||
|
||||
/****************************************************************//**
|
||||
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=false);
|
||||
/*!< in: true if only an error should
|
||||
be produced when decompression fails.
|
||||
By default this parameter is false. */
|
||||
|
||||
/****************************************************************//**
|
||||
Get space id from fil node
|
||||
@return space id*/
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
fil_node_get_space_id(
|
||||
/*==================*/
|
||||
fil_node_t* node); /*!< in: Node where to get space id*/
|
||||
/** 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 compressed page buffer
|
||||
@return size of the compressed data
|
||||
@retval 0 if decompression failed
|
||||
@retval srv_page_size if the page was not compressed */
|
||||
UNIV_INTERN ulint fil_page_decompress(byte* tmp_buf, byte* buf)
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
/****************************************************************//**
|
||||
Get block size from fil node
|
||||
@ -120,13 +76,4 @@ ibool
|
||||
fil_page_is_compressed_encrypted(
|
||||
/*=============================*/
|
||||
byte* buf); /*!< in: page */
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is page compressed with lzo method
|
||||
@return true if page is page compressed with lzo method*/
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_lzo_compressed(
|
||||
/*=======================*/
|
||||
byte* buf); /*!< in: page */
|
||||
#endif
|
||||
|
@ -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
|
||||
@ -49,18 +49,6 @@ fsp_flags_get_atomic_writes(
|
||||
return((atomic_writes_t)FSP_FLAGS_GET_ATOMIC_WRITES(flags));
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is index page or not
|
||||
@return true if page type index page, false if not */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_index_page(
|
||||
/*===================*/
|
||||
byte* buf) /*!< in: page */
|
||||
{
|
||||
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is page compressed
|
||||
@return true if page is page compressed, false if not */
|
||||
@ -84,59 +72,3 @@ fil_page_is_compressed_encrypted(
|
||||
{
|
||||
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Get the name of the compression algorithm used for page
|
||||
compression.
|
||||
@return compression algorithm name or "UNKNOWN" if not known*/
|
||||
UNIV_INLINE
|
||||
const char*
|
||||
fil_get_compression_alg_name(
|
||||
/*=========================*/
|
||||
ulint comp_alg) /*!<in: compression algorithm number */
|
||||
{
|
||||
switch(comp_alg) {
|
||||
case PAGE_UNCOMPRESSED:
|
||||
return ("uncompressed");
|
||||
break;
|
||||
case PAGE_ZLIB_ALGORITHM:
|
||||
return ("ZLIB");
|
||||
break;
|
||||
case PAGE_LZ4_ALGORITHM:
|
||||
return ("LZ4");
|
||||
break;
|
||||
case PAGE_LZO_ALGORITHM:
|
||||
return ("LZO");
|
||||
break;
|
||||
case PAGE_LZMA_ALGORITHM:
|
||||
return ("LZMA");
|
||||
break;
|
||||
case PAGE_BZIP2_ALGORITHM:
|
||||
return ("BZIP2");
|
||||
break;
|
||||
case PAGE_SNAPPY_ALGORITHM:
|
||||
return ("SNAPPY");
|
||||
break;
|
||||
/* No default to get compiler warning */
|
||||
}
|
||||
|
||||
return ("NULL");
|
||||
}
|
||||
|
||||
#ifndef UNIV_INNOCHECKSUM
|
||||
/*******************************************************************//**
|
||||
Find out wheather the page is page compressed with lzo method
|
||||
@return true if page is page compressed with lzo method, false if not */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
fil_page_is_lzo_compressed(
|
||||
/*=======================*/
|
||||
byte* buf) /*!< in: page */
|
||||
{
|
||||
return((mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED &&
|
||||
mach_read_from_8(buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) == PAGE_LZO_ALGORITHM) ||
|
||||
(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED &&
|
||||
mach_read_from_2(buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE) == PAGE_LZO_ALGORITHM));
|
||||
}
|
||||
|
||||
#endif /* UNIV_INNOCHECKSUM */
|
||||
|
@ -42,6 +42,12 @@ Created 2012-02-08 by Sunny Bains.
|
||||
#include "srv0start.h"
|
||||
#include "row0quiesce.h"
|
||||
#include "fil0pagecompress.h"
|
||||
#ifdef HAVE_LZO
|
||||
#include "lzo/lzo1x.h"
|
||||
#endif
|
||||
#ifdef HAVE_SNAPPY
|
||||
#include "snappy-c.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -3364,15 +3370,30 @@ fil_iterate(
|
||||
os_offset_t offset;
|
||||
ulint n_bytes = iter.n_io_buffers * iter.page_size;
|
||||
|
||||
const ulint buf_size = srv_page_size
|
||||
#ifdef HAVE_LZO
|
||||
+ LZO1X_1_15_MEM_COMPRESS
|
||||
#elif defined HAVE_SNAPPY
|
||||
+ snappy_max_compressed_length(srv_page_size)
|
||||
#endif
|
||||
;
|
||||
byte* page_compress_buf = static_cast<byte*>(
|
||||
ut_malloc_low(buf_size, false));
|
||||
ut_ad(!srv_read_only_mode);
|
||||
|
||||
if (!page_compress_buf) {
|
||||
return DB_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* TODO: For ROW_FORMAT=COMPRESSED tables we do a lot of useless
|
||||
copying for non-index pages. Unfortunately, it is
|
||||
required by buf_zip_decompress() */
|
||||
dberr_t err = DB_SUCCESS;
|
||||
|
||||
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
|
||||
if (callback.is_interrupted()) {
|
||||
return DB_INTERRUPTED;
|
||||
err = DB_INTERRUPTED;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
byte* io_buffer = iter.io_buffer;
|
||||
@ -3403,12 +3424,13 @@ fil_iterate(
|
||||
if (!os_file_read_no_error_handling(iter.file, readptr,
|
||||
offset, n_bytes)) {
|
||||
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_read() failed");
|
||||
return DB_IO_ERROR;
|
||||
err = DB_IO_ERROR;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
bool updated = false;
|
||||
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
|
||||
const ulint size = iter.page_size;
|
||||
ulint n_pages_read = ulint(n_bytes) / size;
|
||||
block->page.offset = offset / size;
|
||||
|
||||
for (ulint i = 0; i < n_pages_read;
|
||||
@ -3437,11 +3459,11 @@ page_corrupted:
|
||||
UINT64PF " looks corrupted.",
|
||||
callback.filename(),
|
||||
ulong(offset / size), offset);
|
||||
return DB_CORRUPTION;
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
bool decrypted = false;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
byte* dst = io_buffer + (i * size);
|
||||
bool frame_changed = false;
|
||||
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
|
||||
@ -3450,6 +3472,10 @@ page_corrupted:
|
||||
== FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|
||||
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
|
||||
|
||||
if (page_compressed && block->page.zip.data) {
|
||||
goto page_corrupted;
|
||||
}
|
||||
|
||||
if (!encrypted) {
|
||||
} else if (!mach_read_from_4(
|
||||
FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
|
||||
@ -3475,7 +3501,7 @@ not_encrypted:
|
||||
iter.page_size, src, &err);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return err;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (!decrypted) {
|
||||
@ -3488,8 +3514,12 @@ not_encrypted:
|
||||
/* If the original page is page_compressed, we need
|
||||
to decompress it before adjusting further. */
|
||||
if (page_compressed) {
|
||||
fil_decompress_page(NULL, dst, ulong(size),
|
||||
NULL);
|
||||
ulint compress_length = fil_page_decompress(
|
||||
page_compress_buf, dst);
|
||||
ut_ad(compress_length != srv_page_size);
|
||||
if (compress_length == 0) {
|
||||
goto page_corrupted;
|
||||
}
|
||||
updated = true;
|
||||
} else if (buf_page_is_corrupted(
|
||||
false,
|
||||
@ -3500,7 +3530,7 @@ not_encrypted:
|
||||
}
|
||||
|
||||
if ((err = callback(block)) != DB_SUCCESS) {
|
||||
return err;
|
||||
goto func_exit;
|
||||
} else if (!updated) {
|
||||
updated = buf_block_get_state(block)
|
||||
== BUF_BLOCK_FILE_PAGE;
|
||||
@ -3550,19 +3580,17 @@ not_encrypted:
|
||||
src = io_buffer + (i * size);
|
||||
|
||||
if (page_compressed) {
|
||||
ulint len = 0;
|
||||
|
||||
fil_compress_page(
|
||||
NULL,
|
||||
src,
|
||||
NULL,
|
||||
size,
|
||||
0,/* FIXME: compression level */
|
||||
512,/* FIXME: use proper block size */
|
||||
encrypted,
|
||||
&len);
|
||||
|
||||
updated = true;
|
||||
if (fil_page_compress(
|
||||
src,
|
||||
page_compress_buf,
|
||||
0,/* FIXME: compression level */
|
||||
512,/* FIXME: proper block size */
|
||||
encrypted)) {
|
||||
/* FIXME: remove memcpy() */
|
||||
memcpy(src, page_compress_buf,
|
||||
srv_page_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* If tablespace is encrypted, encrypt page before we
|
||||
@ -3599,11 +3627,14 @@ not_encrypted:
|
||||
offset, (ulint) n_bytes)) {
|
||||
|
||||
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
|
||||
return DB_IO_ERROR;
|
||||
err = DB_IO_ERROR;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
return DB_SUCCESS;
|
||||
func_exit:
|
||||
ut_free(page_compress_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
|
Loading…
x
Reference in New Issue
Block a user