Commit d9044d11 authored by marko's avatar marko

branches/zip: When setting the PAGE_LEVEL of a compressed B-tree page

from or to 0, compress the page at the same time.  This is necessary,
because the column information stored on the compressed page will
differ between leaf and non-leaf pages.  Leaf pages are identified by
PAGE_LEVEL=0.  This bug was reported as Issue #150.

Document the similarity between btr_page_create() and
btr_page_empty().  Make the function signature of btr_page_empty()
identical with btr_page_create().  (This will add the parameter "level".)

btr_root_raise_and_insert(): Replace some code with a call to
btr_page_empty().

btr_attach_half_pages(): Assert that the page level has already been
set on both block and new_block.  Do not set it again.

btr_discard_only_page_on_level(): Document that this function is
probably never called.  Make it work on any height tree.  (Tested on
2-high tree by disabling btr_lift_page_up().)

rb://68
parent d4d4e502
......@@ -263,7 +263,7 @@ btr_get_next_user_rec(
/******************************************************************
Creates a new index page (not the root, and also not
used in page reorganization). */
used in page reorganization). @see btr_page_empty(). */
static
void
btr_page_create(
......@@ -1065,19 +1065,21 @@ btr_parse_page_reorganize(
}
/*****************************************************************
Empties an index page. */
Empties an index page. @see btr_page_create().*/
static
void
btr_page_empty(
/*===========*/
buf_block_t* block, /* in: page to be emptied */
page_zip_des_t* page_zip,/* out: compressed page, or NULL */
mtr_t* mtr, /* in: mtr */
dict_index_t* index) /* in: index of the page */
dict_index_t* index, /* in: index of the page */
ulint level, /* in: the B-tree level of the page */
mtr_t* mtr) /* in: mtr */
{
page_t* page = buf_block_get_frame(block);
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
ut_ad(page_zip == buf_block_get_page_zip(block));
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
......@@ -1088,10 +1090,10 @@ btr_page_empty(
segment headers, next page-field, etc.) is preserved intact */
if (UNIV_LIKELY_NULL(page_zip)) {
page_create_zip(block, index,
btr_page_get_level(page, mtr), mtr);
page_create_zip(block, index, level, mtr);
} else {
page_create(block, mtr, dict_table_is_comp(index->table));
btr_page_set_level(page, NULL, level, mtr);
}
block->check_index_page_at_flush = TRUE;
......@@ -1153,7 +1155,6 @@ btr_root_raise_and_insert(
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(mtr, root_block, MTR_MEMO_PAGE_X_FIX));
btr_search_drop_page_hash_index(root_block);
/* Allocate a new page to the tree. Root splitting is done by first
moving the root records to the new page, emptying the root, putting
......@@ -1226,12 +1227,7 @@ btr_root_raise_and_insert(
| REC_INFO_MIN_REC_FLAG);
/* Rebuild the root page to get free space */
if (UNIV_LIKELY_NULL(root_page_zip)) {
page_create_zip(root_block, index, level + 1, mtr);
} else {
page_create(root_block, mtr, dict_table_is_comp(index->table));
btr_page_set_level(root, NULL, level + 1, mtr);
}
btr_page_empty(root_block, root_page_zip, index, level + 1, mtr);
/* Set the next node and previous node fields, although
they should already have been set. The previous node field
......@@ -1241,8 +1237,6 @@ btr_root_raise_and_insert(
btr_page_set_next(root, root_page_zip, FIL_NULL, mtr);
btr_page_set_prev(root, root_page_zip, FIL_NULL, mtr);
root_block->check_index_page_at_flush = TRUE;
page_cursor = btr_cur_get_page_cur(cursor);
/* Insert node pointer to the root */
......@@ -1700,6 +1694,8 @@ btr_attach_half_pages(
/* Get the level of the split pages */
level = btr_page_get_level(buf_block_get_frame(block), mtr);
ut_ad(level
== btr_page_get_level(buf_block_get_frame(new_block), mtr));
/* Build the node pointer (= node key and page address) for the upper
half */
......@@ -1756,11 +1752,9 @@ btr_attach_half_pages(
btr_page_set_prev(lower_page, lower_page_zip, prev_page_no, mtr);
btr_page_set_next(lower_page, lower_page_zip, upper_page_no, mtr);
btr_page_set_level(lower_page, lower_page_zip, level, mtr);
btr_page_set_prev(upper_page, upper_page_zip, lower_page_no, mtr);
btr_page_set_next(upper_page, upper_page_zip, next_page_no, mtr);
btr_page_set_level(upper_page, upper_page_zip, level, mtr);
}
/*****************************************************************
......@@ -2364,11 +2358,7 @@ btr_lift_page_up(
btr_search_drop_page_hash_index(block);
/* Make the father empty */
btr_page_empty(father_block, father_page_zip, mtr, index);
/* Set the level before inserting records, because
page_zip_compress() requires that the first user record
on a non-leaf page has the min_rec_mark set. */
btr_page_set_level(father_page, father_page_zip, page_level, mtr);
btr_page_empty(father_block, father_page_zip, index, page_level, mtr);
/* Copy the records to the father page one by one. */
if (0
......@@ -2415,7 +2405,7 @@ btr_lift_page_up(
/* Free the file page */
btr_page_free(index, block, mtr);
/* We play safe and reset the free bits for the father */
/* We play it safe and reset the free bits for the father */
if (!dict_index_is_clust(index)) {
ibuf_reset_free_bits(father_block);
}
......@@ -2716,7 +2706,10 @@ btr_compress(
}
/*****************************************************************
Discards a page that is the only page on its level. */
Discards a page that is the only page on its level. This will empty
the whole B-tree, leaving just an empty root page. This function
should never be reached, because btr_compress(), which is invoked in
delete operations, calls btr_lift_page_up() to flatten the B-tree. */
static
void
btr_discard_only_page_on_level(
......@@ -2725,60 +2718,52 @@ btr_discard_only_page_on_level(
buf_block_t* block, /* in: page which is the only on its level */
mtr_t* mtr) /* in: mtr */
{
btr_cur_t father_cursor;
buf_block_t* father_block;
page_t* father_page;
page_zip_des_t* father_page_zip;
page_t* page = buf_block_get_frame(block);
ulint page_level;
ulint page_level = 0;
ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
btr_search_drop_page_hash_index(block);
while (buf_block_get_page_no(block) != dict_index_get_page(index)) {
btr_cur_t cursor;
buf_block_t* father;
const page_t* page = buf_block_get_frame(block);
btr_page_get_father(index, block, mtr, &father_cursor);
father_block = btr_cur_get_block(&father_cursor);
father_page_zip = buf_block_get_page_zip(father_block);
father_page = buf_block_get_frame(father_block);
ut_a(page_get_n_recs(page) == 1);
ut_a(page_level == btr_page_get_level(page, mtr));
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
page_level = btr_page_get_level(page, mtr);
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
btr_search_drop_page_hash_index(block);
lock_update_discard(father_block, PAGE_HEAP_NO_SUPREMUM, block);
btr_page_get_father(index, block, mtr, &cursor);
father = btr_cur_get_block(&cursor);
btr_page_set_level(father_page, father_page_zip, page_level, mtr);
lock_update_discard(father, PAGE_HEAP_NO_SUPREMUM, block);
/* Free the file page */
btr_page_free(index, block, mtr);
/* Free the file page */
btr_page_free(index, block, mtr);
if (UNIV_LIKELY(buf_block_get_page_no(father_block)
== dict_index_get_page(index))) {
/* The father is the root page */
block = father;
page_level++;
}
/* block is the root page, which must be empty, except
for the node pointer to the (now discarded) block(s). */
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
const page_t* root
= buf_block_get_frame(father_block);
const ulint space
= dict_index_get_space(index);
ut_a(btr_root_fseg_validate(
FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ root, space));
ut_a(btr_root_fseg_validate(
FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ root, space));
}
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
const ulint space = dict_index_get_space(index);
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ root, space));
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ root, space));
}
#endif /* UNIV_BTR_DEBUG */
btr_page_empty(father_block, father_page_zip, mtr, index);
/* We play safe and reset the free bits for the father */
if (!dict_index_is_clust(index)) {
ibuf_reset_free_bits(father_block);
}
} else {
ut_ad(page_get_n_recs(father_page) == 1);
btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr);
btr_discard_only_page_on_level(index, father_block, mtr);
/* We play it safe and reset the free bits for the root */
if (!dict_index_is_clust(index)) {
ibuf_reset_free_bits(block);
}
}
......
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