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 2009-09-28 The InnoDB Team
* fil/fil0fil.c: * fil/fil0fil.c:
......
...@@ -1011,7 +1011,26 @@ btr_page_reorganize_low( ...@@ -1011,7 +1011,26 @@ btr_page_reorganize_low(
(!page_zip_compress(page_zip, page, index, NULL))) { (!page_zip_compress(page_zip, page, index, NULL))) {
/* Restore the old page and exit. */ /* 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; goto func_exit;
} }
......
...@@ -1834,7 +1834,7 @@ buf_zip_decompress( ...@@ -1834,7 +1834,7 @@ buf_zip_decompress(
switch (fil_page_get_type(frame)) { switch (fil_page_get_type(frame)) {
case FIL_PAGE_INDEX: case FIL_PAGE_INDEX:
if (page_zip_decompress(&block->page.zip, if (page_zip_decompress(&block->page.zip,
block->frame)) { block->frame, TRUE)) {
return(TRUE); return(TRUE);
} }
......
...@@ -76,8 +76,11 @@ typedef byte page_header_t; ...@@ -76,8 +76,11 @@ typedef byte page_header_t;
header which are set in a page create */ header which are set in a page create */
/*----*/ /*----*/
#define PAGE_LEVEL 26 /* level of the node in an index tree; the #define PAGE_LEVEL 26 /* level of the node in an index tree; the
leaf level is the level 0 */ leaf level is the level 0. This field should
#define PAGE_INDEX_ID 28 /* index id where the page belongs */ 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 #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 a B-tree: defined only on the root page of a
B-tree, but not in the root of an ibuf tree */ B-tree, but not in the root of an ibuf tree */
......
...@@ -127,8 +127,12 @@ page_zip_decompress( ...@@ -127,8 +127,12 @@ page_zip_decompress(
/*================*/ /*================*/
page_zip_des_t* page_zip,/*!< in: data, ssize; page_zip_des_t* page_zip,/*!< in: data, ssize;
out: m_start, m_end, m_nonempty, n_blobs */ 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 */
__attribute__((nonnull)); 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 #ifdef UNIV_DEBUG
/**********************************************************************//** /**********************************************************************//**
...@@ -385,8 +389,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a ...@@ -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 non-clustered index, the caller must update the insert buffer free
bits in the same mini-transaction in such a way that the modification bits in the same mini-transaction in such a way that the modification
will be redo-logged. will be redo-logged.
@return TRUE on success, FALSE on failure; page and page_zip will be @return TRUE on success, FALSE on failure; page_zip will be left
left intact on failure. */ intact on failure, but page will be overwritten. */
UNIV_INTERN UNIV_INTERN
ibool ibool
page_zip_reorganize( page_zip_reorganize(
......
...@@ -1195,7 +1195,7 @@ page_cur_insert_rec_zip_reorg( ...@@ -1195,7 +1195,7 @@ page_cur_insert_rec_zip_reorg(
} }
/* Out of space: restore the page */ /* 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_error; /* Memory corrupted? */
} }
ut_ad(page_validate(page, index)); ut_ad(page_validate(page, index));
......
...@@ -679,7 +679,7 @@ page_copy_rec_list_end( ...@@ -679,7 +679,7 @@ page_copy_rec_list_end(
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip, (!page_zip_decompress(new_page_zip,
new_page))) { new_page, FALSE))) {
ut_error; ut_error;
} }
ut_ad(page_validate(new_page, index)); ut_ad(page_validate(new_page, index));
...@@ -792,7 +792,7 @@ page_copy_rec_list_start( ...@@ -792,7 +792,7 @@ page_copy_rec_list_start(
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip, (!page_zip_decompress(new_page_zip,
new_page))) { new_page, FALSE))) {
ut_error; ut_error;
} }
ut_ad(page_validate(new_page, index)); ut_ad(page_validate(new_page, index));
......
...@@ -2821,7 +2821,11 @@ page_zip_decompress( ...@@ -2821,7 +2821,11 @@ page_zip_decompress(
/*================*/ /*================*/
page_zip_des_t* page_zip,/*!< in: data, ssize; page_zip_des_t* page_zip,/*!< in: data, ssize;
out: m_start, m_end, m_nonempty, n_blobs */ 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; z_stream d_stream;
dict_index_t* index = NULL; dict_index_t* index = NULL;
...@@ -2851,13 +2855,36 @@ page_zip_decompress( ...@@ -2851,13 +2855,36 @@ page_zip_decompress(
heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE); heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE);
recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)); 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 #ifdef UNIV_ZIP_DEBUG
/* Clear the page. */ /* Clear the uncompressed page, except the header. */
memset(page, 0x55, UNIV_PAGE_SIZE); memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA);
#endif /* UNIV_ZIP_DEBUG */ #endif /* UNIV_ZIP_DEBUG */
UNIV_MEM_INVALID(page, UNIV_PAGE_SIZE); UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA);
/* Copy the page header. */
memcpy(page, page_zip->data, PAGE_DATA);
/* Copy the page directory. */ /* Copy the page directory. */
if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs, if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs,
...@@ -3098,7 +3125,7 @@ page_zip_validate_low( ...@@ -3098,7 +3125,7 @@ page_zip_validate_low(
#endif /* UNIV_DEBUG_VALGRIND */ #endif /* UNIV_DEBUG_VALGRIND */
temp_page_zip = *page_zip; 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) { if (!valid) {
fputs("page_zip_validate(): failed to decompress\n", stderr); fputs("page_zip_validate(): failed to decompress\n", stderr);
goto func_exit; goto func_exit;
...@@ -4376,8 +4403,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a ...@@ -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 non-clustered index, the caller must update the insert buffer free
bits in the same mini-transaction in such a way that the modification bits in the same mini-transaction in such a way that the modification
will be redo-logged. will be redo-logged.
@return TRUE on success, FALSE on failure; page and page_zip will be @return TRUE on success, FALSE on failure; page_zip will be left
left intact on failure. */ intact on failure, but page will be overwritten. */
UNIV_INTERN UNIV_INTERN
ibool ibool
page_zip_reorganize( page_zip_reorganize(
...@@ -4442,9 +4469,6 @@ page_zip_reorganize( ...@@ -4442,9 +4469,6 @@ page_zip_reorganize(
if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) { 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 #ifndef UNIV_HOTBACKUP
buf_block_free(temp_block); buf_block_free(temp_block);
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
...@@ -4605,7 +4629,8 @@ corrupt: ...@@ -4605,7 +4629,8 @@ corrupt:
memcpy(page_zip->data + page_zip_get_size(page_zip) memcpy(page_zip->data + page_zip_get_size(page_zip)
- trailer_size, ptr + 8 + size, trailer_size); - 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; 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