Commit 3b38bf02 authored by marko's avatar marko

branches/zip: Do not write to PAGE_INDEX_ID after page creation,

not even when restoring an uncompressed page after a compression failure.

btr_page_reorganize_low(): On compression failure, do not restore
those page header fields that should not be affected by the
reorganization.  Instead, compare the fields.

page_zip_decompress(): Add the parameter ibool all, for copying all
page header fields.  Pass the parameter all=TRUE on block read
completion, redo log application, and page_zip_validate(); pass
all=FALSE in all other cases.

page_zip_reorganize(): Do not restore the uncompressed page on
failure.  It will be restored (to pre-modification state) by the
caller anyway.

rb://167, Issue #346
parent e5f47441
2009-09-28 The InnoDB Team
* btr/btr0btr.c, buf/buf0buf.c,
include/page0page.h, include/page0zip.h,
page/page0cur.c, page/page0page.c, page/page0zip.c:
Do not write to PAGE_INDEX_ID when restoring an uncompressed page
after a compression failure. The field should only be written
when creating a B-tree page. This fix addresses a race condition
in a debug assertion.
2009-09-28 The InnoDB Team
* fil/fil0fil.c:
......
......@@ -1011,7 +1011,26 @@ btr_page_reorganize_low(
(!page_zip_compress(page_zip, page, index, NULL))) {
/* Restore the old page and exit. */
buf_frame_copy(page, temp_page);
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
/* Check that the bytes that we skip are identical. */
ut_a(!memcmp(page, temp_page, PAGE_HEADER));
ut_a(!memcmp(PAGE_HEADER + PAGE_N_RECS + page,
PAGE_HEADER + PAGE_N_RECS + temp_page,
PAGE_DATA - (PAGE_HEADER + PAGE_N_RECS)));
ut_a(!memcmp(UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page,
UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + temp_page,
FIL_PAGE_DATA_END));
#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
memcpy(PAGE_HEADER + page, PAGE_HEADER + temp_page,
PAGE_N_RECS - PAGE_N_DIR_SLOTS);
memcpy(PAGE_DATA + page, PAGE_DATA + temp_page,
UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END);
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
ut_a(!memcmp(page, temp_page, UNIV_PAGE_SIZE));
#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
goto func_exit;
}
......
......@@ -1834,7 +1834,7 @@ buf_zip_decompress(
switch (fil_page_get_type(frame)) {
case FIL_PAGE_INDEX:
if (page_zip_decompress(&block->page.zip,
block->frame)) {
block->frame, TRUE)) {
return(TRUE);
}
......
......@@ -76,8 +76,11 @@ typedef byte page_header_t;
header which are set in a page create */
/*----*/
#define PAGE_LEVEL 26 /* level of the node in an index tree; the
leaf level is the level 0 */
#define PAGE_INDEX_ID 28 /* index id where the page belongs */
leaf level is the level 0. This field should
not be written to after page creation. */
#define PAGE_INDEX_ID 28 /* index id where the page belongs.
This field should not be written to after
page creation. */
#define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in
a B-tree: defined only on the root page of a
B-tree, but not in the root of an ibuf tree */
......
......@@ -127,8 +127,12 @@ page_zip_decompress(
/*================*/
page_zip_des_t* page_zip,/*!< in: data, ssize;
out: m_start, m_end, m_nonempty, n_blobs */
page_t* page) /*!< out: uncompressed page, may be trashed */
__attribute__((nonnull));
page_t* page, /*!< out: uncompressed page, may be trashed */
ibool all) /*!< in: TRUE=decompress the whole page;
FALSE=verify but do not copy some
page header fields that should not change
after page creation */
__attribute__((nonnull(1,2)));
#ifdef UNIV_DEBUG
/**********************************************************************//**
......@@ -385,8 +389,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a
non-clustered index, the caller must update the insert buffer free
bits in the same mini-transaction in such a way that the modification
will be redo-logged.
@return TRUE on success, FALSE on failure; page and page_zip will be
left intact on failure. */
@return TRUE on success, FALSE on failure; page_zip will be left
intact on failure, but page will be overwritten. */
UNIV_INTERN
ibool
page_zip_reorganize(
......
......@@ -1195,7 +1195,7 @@ page_cur_insert_rec_zip_reorg(
}
/* Out of space: restore the page */
if (!page_zip_decompress(page_zip, page)) {
if (!page_zip_decompress(page_zip, page, FALSE)) {
ut_error; /* Memory corrupted? */
}
ut_ad(page_validate(page, index));
......
......@@ -679,7 +679,7 @@ page_copy_rec_list_end(
if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip,
new_page))) {
new_page, FALSE))) {
ut_error;
}
ut_ad(page_validate(new_page, index));
......@@ -792,7 +792,7 @@ page_copy_rec_list_start(
if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip,
new_page))) {
new_page, FALSE))) {
ut_error;
}
ut_ad(page_validate(new_page, index));
......
......@@ -2821,7 +2821,11 @@ page_zip_decompress(
/*================*/
page_zip_des_t* page_zip,/*!< in: data, ssize;
out: m_start, m_end, m_nonempty, n_blobs */
page_t* page) /*!< out: uncompressed page, may be trashed */
page_t* page, /*!< out: uncompressed page, may be trashed */
ibool all) /*!< in: TRUE=decompress the whole page;
FALSE=verify but do not copy some
page header fields that should not change
after page creation */
{
z_stream d_stream;
dict_index_t* index = NULL;
......@@ -2851,13 +2855,36 @@ page_zip_decompress(
heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE);
recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs));
if (all) {
/* Copy the page header. */
memcpy(page, page_zip->data, PAGE_DATA);
} else {
/* Check that the bytes that we skip are identical. */
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
ut_a(!memcmp(FIL_PAGE_TYPE + page,
FIL_PAGE_TYPE + page_zip->data,
PAGE_HEADER - FIL_PAGE_TYPE));
ut_a(!memcmp(PAGE_HEADER + PAGE_LEVEL + page,
PAGE_HEADER + PAGE_LEVEL + page_zip->data,
PAGE_DATA - (PAGE_HEADER + PAGE_LEVEL)));
#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
/* Copy the mutable parts of the page header. */
memcpy(page, page_zip->data, FIL_PAGE_TYPE);
memcpy(PAGE_HEADER + page, PAGE_HEADER + page_zip->data,
PAGE_LEVEL - PAGE_N_DIR_SLOTS);
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
/* Check that the page headers match after copying. */
ut_a(!memcmp(page, page_zip->data, PAGE_DATA));
#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
}
#ifdef UNIV_ZIP_DEBUG
/* Clear the page. */
memset(page, 0x55, UNIV_PAGE_SIZE);
/* Clear the uncompressed page, except the header. */
memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA);
#endif /* UNIV_ZIP_DEBUG */
UNIV_MEM_INVALID(page, UNIV_PAGE_SIZE);
/* Copy the page header. */
memcpy(page, page_zip->data, PAGE_DATA);
UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA);
/* Copy the page directory. */
if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs,
......@@ -3098,7 +3125,7 @@ page_zip_validate_low(
#endif /* UNIV_DEBUG_VALGRIND */
temp_page_zip = *page_zip;
valid = page_zip_decompress(&temp_page_zip, temp_page);
valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE);
if (!valid) {
fputs("page_zip_validate(): failed to decompress\n", stderr);
goto func_exit;
......@@ -4376,8 +4403,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a
non-clustered index, the caller must update the insert buffer free
bits in the same mini-transaction in such a way that the modification
will be redo-logged.
@return TRUE on success, FALSE on failure; page and page_zip will be
left intact on failure. */
@return TRUE on success, FALSE on failure; page_zip will be left
intact on failure, but page will be overwritten. */
UNIV_INTERN
ibool
page_zip_reorganize(
......@@ -4442,9 +4469,6 @@ page_zip_reorganize(
if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
/* Restore the old page and exit. */
buf_frame_copy(page, temp_page);
#ifndef UNIV_HOTBACKUP
buf_block_free(temp_block);
#endif /* !UNIV_HOTBACKUP */
......@@ -4605,7 +4629,8 @@ page_zip_parse_compress(
memcpy(page_zip->data + page_zip_get_size(page_zip)
- trailer_size, ptr + 8 + size, trailer_size);
if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page))) {
if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page,
TRUE))) {
goto corrupt;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment