Skip to content

Commit

Permalink
MDEV-9242: Innodb reports Assertion failure in file buf0dblwr.cc line…
Browse files Browse the repository at this point in the history
… 579

Analysis: When pages in doublewrite buffer are analyzed compressed
pages do not have correct checksum.

Fix: Decompress page before checksum is compared. If decompression
fails we still check checksum and corrupted pages are found.
If decompression succeeds, page now contains the original
checksum.
  • Loading branch information
Jan Lindström committed Apr 29, 2016
1 parent d5822a3 commit 037b78e
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 10 deletions.
24 changes: 23 additions & 1 deletion storage/innobase/buf/buf0dblwr.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -37,6 +37,7 @@ Created 2011/12/19
#include "page0zip.h"
#include "trx0sys.h"
#include "fil0crypt.h"
#include "fil0pagecompress.h"

#ifndef UNIV_HOTBACKUP

Expand Down Expand Up @@ -500,6 +501,7 @@ buf_dblwr_process()

for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
bool is_compressed = false;

page = *i;
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
Expand Down Expand Up @@ -533,6 +535,16 @@ buf_dblwr_process()
NULL,
0);

/* Is page compressed ? */
is_compressed = fil_page_is_compressed_encrypted(read_buf) |
fil_page_is_compressed(read_buf);

/* If page was compressed, decompress it before we
check checksum. */
if (is_compressed) {
fil_decompress_page(NULL, read_buf, UNIV_PAGE_SIZE, NULL, true);
}

if (fil_space_verify_crypt_checksum(read_buf, zip_size)) {
/* page is encrypted and checksum is OK */
} else if (buf_page_is_corrupted(true, read_buf, zip_size)) {
Expand All @@ -546,6 +558,16 @@ buf_dblwr_process()
" the doublewrite buffer.\n",
(ulong) space_id, (ulong) page_no);

/* Is page compressed ? */
is_compressed = fil_page_is_compressed_encrypted(page) |
fil_page_is_compressed(page);

/* If page was compressed, decompress it before we
check checksum. */
if (is_compressed) {
fil_decompress_page(NULL, page, UNIV_PAGE_SIZE, NULL, true);
}

if (fil_space_verify_crypt_checksum(page, zip_size)) {
/* the doublewrite buffer page is encrypted and OK */
} else if (buf_page_is_corrupted(true,
Expand Down
35 changes: 33 additions & 2 deletions storage/innobase/fil/fil0pagecompress.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (C) 2013, 2015, MariaDB Corporation. All Rights Reserved.
Copyright (C) 2013, 2016, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -447,8 +447,11 @@ fil_decompress_page(
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
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. */
{
int err = 0;
ulint actual_size = 0;
Expand Down Expand Up @@ -493,6 +496,9 @@ fil_decompress_page(
mach_read_from_2(buf+FIL_PAGE_TYPE), len);

fflush(stderr);
if (return_error) {
goto error_return;
}
ut_error;
}

Expand All @@ -512,6 +518,9 @@ fil_decompress_page(
" actual size %lu compression %s.",
actual_size, fil_get_compression_alg_name(compression_alg));
fflush(stderr);
if (return_error) {
goto error_return;
}
ut_error;
}

Expand Down Expand Up @@ -543,6 +552,9 @@ fil_decompress_page(

fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -559,6 +571,9 @@ fil_decompress_page(
err, actual_size, len);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -577,6 +592,9 @@ fil_decompress_page(
olen, actual_size, len);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand Down Expand Up @@ -610,6 +628,9 @@ fil_decompress_page(
dst_pos, actual_size, len);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}

Expand All @@ -636,6 +657,9 @@ fil_decompress_page(
dst_pos, actual_size, len, err);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -661,6 +685,9 @@ fil_decompress_page(
olen, actual_size, len, (int)cstatus);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -674,6 +701,9 @@ fil_decompress_page(
,fil_get_compression_alg_name(compression_alg));

fflush(stderr);
if (return_error) {
goto error_return;
}
ut_error;
break;
}
Expand All @@ -684,6 +714,7 @@ fil_decompress_page(
really any other options. */
memcpy(buf, in_buf, len);

error_return:
// Need to free temporal buffer if no buffer was given
if (page_buf == NULL) {
ut_free(in_buf);
Expand Down
8 changes: 6 additions & 2 deletions storage/innobase/include/fil0pagecompress.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (C) 2013, 2015 MariaDB Corporation. All Rights Reserved.
Copyright (C) 2013, 2016 MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -117,8 +117,12 @@ fil_decompress_page(
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
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
Expand Down
24 changes: 23 additions & 1 deletion storage/xtradb/buf/buf0dblwr.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -37,6 +37,7 @@ Created 2011/12/19
#include "page0zip.h"
#include "trx0sys.h"
#include "fil0crypt.h"
#include "fil0pagecompress.h"

#ifndef UNIV_HOTBACKUP

Expand Down Expand Up @@ -500,6 +501,7 @@ buf_dblwr_process()

for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
bool is_compressed = false;

page = *i;
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
Expand Down Expand Up @@ -533,6 +535,16 @@ buf_dblwr_process()
NULL,
0);

/* Is page compressed ? */
is_compressed = fil_page_is_compressed_encrypted(read_buf) |
fil_page_is_compressed(read_buf);

/* If page was compressed, decompress it before we
check checksum. */
if (is_compressed) {
fil_decompress_page(NULL, read_buf, UNIV_PAGE_SIZE, NULL, true);
}

if (fil_space_verify_crypt_checksum(read_buf, zip_size)) {
/* page is encrypted and checksum is OK */
} else if (buf_page_is_corrupted(true, read_buf, zip_size)) {
Expand All @@ -546,6 +558,16 @@ buf_dblwr_process()
" the doublewrite buffer.\n",
(ulong) space_id, (ulong) page_no);

/* Is page compressed ? */
is_compressed = fil_page_is_compressed_encrypted(page) |
fil_page_is_compressed(page);

/* If page was compressed, decompress it before we
check checksum. */
if (is_compressed) {
fil_decompress_page(NULL, page, UNIV_PAGE_SIZE, NULL, true);
}

if (fil_space_verify_crypt_checksum(page, zip_size)) {
/* the doublewrite buffer page is encrypted and OK */
} else if (buf_page_is_corrupted(true,
Expand Down
35 changes: 33 additions & 2 deletions storage/xtradb/fil/fil0pagecompress.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (C) 2013, 2015, MariaDB Corporation. All Rights Reserved.
Copyright (C) 2013, 2016, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -446,8 +446,11 @@ fil_decompress_page(
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
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. */
{
int err = 0;
ulint actual_size = 0;
Expand Down Expand Up @@ -492,6 +495,9 @@ fil_decompress_page(
mach_read_from_2(buf+FIL_PAGE_TYPE), len);

fflush(stderr);
if (return_error) {
goto error_return;
}
ut_error;
}

Expand All @@ -511,6 +517,9 @@ fil_decompress_page(
" actual size %lu compression %s.",
actual_size, fil_get_compression_alg_name(compression_alg));
fflush(stderr);
if (return_error) {
goto error_return;
}
ut_error;
}

Expand Down Expand Up @@ -542,6 +551,9 @@ fil_decompress_page(

fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -558,6 +570,9 @@ fil_decompress_page(
err, actual_size, len);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -576,6 +591,9 @@ fil_decompress_page(
olen, actual_size, len);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand Down Expand Up @@ -609,6 +627,9 @@ fil_decompress_page(
dst_pos, actual_size, len);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}

Expand All @@ -635,6 +656,9 @@ fil_decompress_page(
dst_pos, actual_size, len, err);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -660,6 +684,9 @@ fil_decompress_page(
olen, actual_size, len, (int)cstatus);
fflush(stderr);

if (return_error) {
goto error_return;
}
ut_error;
}
break;
Expand All @@ -673,6 +700,9 @@ fil_decompress_page(
,fil_get_compression_alg_name(compression_alg));

fflush(stderr);
if (return_error) {
goto error_return;
}
ut_error;
break;
}
Expand All @@ -683,6 +713,7 @@ fil_decompress_page(
really any other options. */
memcpy(buf, in_buf, len);

error_return:
// Need to free temporal buffer if no buffer was given
if (page_buf == NULL) {
ut_free(in_buf);
Expand Down
8 changes: 6 additions & 2 deletions storage/xtradb/include/fil0pagecompress.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (C) 2013, 2015 MariaDB Corporation. All Rights Reserved.
Copyright (C) 2013, 2016 MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -117,8 +117,12 @@ fil_decompress_page(
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
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
Expand Down

0 comments on commit 037b78e

Please sign in to comment.