📄 btr0btr.c
字号:
Parses the redo log record for setting an index record as the predefinedminimum record. */byte*btr_parse_set_min_rec_mark(/*=======================*/ /* out: end of log record or NULL */ byte* ptr, /* in: buffer */ byte* end_ptr,/* in: buffer end */ ulint comp, /* in: nonzero=compact page format */ page_t* page, /* in: page or NULL */ mtr_t* mtr) /* in: mtr or NULL */{ rec_t* rec; if (end_ptr < ptr + 2) { return(NULL); } if (page) { ut_a(!page_is_comp(page) == !comp); rec = page + mach_read_from_2(ptr); btr_set_min_rec_mark(rec, comp, mtr); } return(ptr + 2);}/********************************************************************Sets a record as the predefined minimum record. */voidbtr_set_min_rec_mark(/*=================*/ rec_t* rec, /* in: record */ ulint comp, /* in: nonzero=compact page format */ mtr_t* mtr) /* in: mtr */{ ulint info_bits; info_bits = rec_get_info_bits(rec, comp); rec_set_info_bits(rec, comp, info_bits | REC_INFO_MIN_REC_FLAG); btr_set_min_rec_mark_log(rec, comp, mtr);}/*****************************************************************Deletes on the upper level the node pointer to a page. */voidbtr_node_ptr_delete(/*================*/ dict_tree_t* tree, /* in: index tree */ page_t* page, /* in: page whose node pointer is deleted */ mtr_t* mtr) /* in: mtr */{ rec_t* node_ptr; btr_cur_t cursor; ibool compressed; ulint err; ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); /* Delete node pointer on father page */ node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr, &cursor); compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE, mtr); ut_a(err == DB_SUCCESS); if (!compressed) { btr_cur_compress_if_useful(&cursor, mtr); }}/*****************************************************************If page is the only on its level, this function moves its records to thefather page, thus reducing the tree height. */staticvoidbtr_lift_page_up(/*=============*/ dict_tree_t* tree, /* in: index tree */ page_t* page, /* in: page which is the only on its level; must not be empty: use btr_discard_only_page_on_level if the last record from the page should be removed */ mtr_t* mtr) /* in: mtr */{ page_t* father_page; ulint page_level; dict_index_t* index; 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, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); father_page = buf_frame_align( btr_page_get_father_node_ptr(tree, page, mtr)); page_level = btr_page_get_level(page, mtr); index = UT_LIST_GET_FIRST(tree->tree_indexes); btr_search_drop_page_hash_index(page); /* Make the father empty */ btr_page_empty(father_page, mtr); /* Move records to the father */ page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page), index, mtr); lock_update_copy_and_discard(father_page, page); btr_page_set_level(father_page, page_level, mtr); /* Free the file page */ btr_page_free(tree, page, mtr); /* We play safe and reset the free bits for the father */ ibuf_reset_free_bits(index, father_page); ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(tree, father_page, mtr));} /*****************************************************************Tries to merge the page first to the left immediate brother if such abrother exists, and the node pointers to the current page and to the brotherreside on the same page. If the left brother does not satisfy theseconditions, looks at the right brother. If the page is the only one on thatlevel lifts the records of the page to the father page, thus reducing thetree height. It is assumed that mtr holds an x-latch on the tree and on thepage. If cursor is on the leaf level, mtr must also hold x-latches to thebrothers, if they exist. NOTE: it is assumed that the caller has reservedenough free extents so that the compression will always succeed if done! */voidbtr_compress(/*=========*/ btr_cur_t* cursor, /* in: cursor on the page to merge or lift; the page must not be empty: in record delete use btr_discard_page if the page would become empty */ mtr_t* mtr) /* in: mtr */{ dict_tree_t* tree; ulint space; ulint left_page_no; ulint right_page_no; page_t* merge_page; page_t* father_page; ibool is_left; page_t* page; rec_t* orig_pred; rec_t* orig_succ; rec_t* node_ptr; ulint data_size; ulint n_recs; ulint max_ins_size; ulint max_ins_size_reorg; ulint level; ulint comp; page = btr_cur_get_page(cursor); tree = btr_cur_get_tree(cursor); comp = page_is_comp(page); ut_a((ibool)!!comp == cursor->index->table->comp); ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); level = btr_page_get_level(page, mtr); space = dict_tree_get_space(tree); left_page_no = btr_page_get_prev(page, mtr); right_page_no = btr_page_get_next(page, mtr);/* fprintf(stderr, "Merge left page %lu right %lu \n", left_page_no, right_page_no); */ node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); ut_ad(!comp || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR); father_page = buf_frame_align(node_ptr); ut_a(comp == page_is_comp(father_page)); /* Decide the page to which we try to merge and which will inherit the locks */ if (left_page_no != FIL_NULL) { is_left = TRUE; merge_page = btr_page_get(space, left_page_no, RW_X_LATCH, mtr); } else if (right_page_no != FIL_NULL) { is_left = FALSE; merge_page = btr_page_get(space, right_page_no, RW_X_LATCH, mtr); } else { /* The page is the only one on the level, lift the records to the father */ btr_lift_page_up(tree, page, mtr); return; } n_recs = page_get_n_recs(page); data_size = page_get_data_size(page); ut_a(page_is_comp(merge_page) == comp); max_ins_size_reorg = page_get_max_insert_size_after_reorganize( merge_page, n_recs); if (data_size > max_ins_size_reorg) { /* No space for merge */ return; } ut_ad(page_validate(merge_page, cursor->index)); max_ins_size = page_get_max_insert_size(merge_page, n_recs); if (data_size > max_ins_size) { /* We have to reorganize merge_page */ btr_page_reorganize(merge_page, cursor->index, mtr); max_ins_size = page_get_max_insert_size(merge_page, n_recs); ut_ad(page_validate(merge_page, cursor->index)); ut_ad(page_get_max_insert_size(merge_page, n_recs) == max_ins_size_reorg); } if (data_size > max_ins_size) { /* Add fault tolerance, though this should never happen */ return; } btr_search_drop_page_hash_index(page); /* Remove the page from the level list */ btr_level_list_remove(tree, page, mtr); if (is_left) { btr_node_ptr_delete(tree, page, mtr); } else { mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; *offsets_ = (sizeof offsets_) / sizeof *offsets_; /* Replace the address of the old child node (= page) with the address of the merge page to the right */ btr_node_ptr_set_child_page_no(node_ptr, rec_get_offsets(node_ptr, cursor->index, offsets_, ULINT_UNDEFINED, &heap), right_page_no, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } btr_node_ptr_delete(tree, merge_page, mtr); } /* Move records to the merge page */ if (is_left) { orig_pred = page_rec_get_prev( page_get_supremum_rec(merge_page)); page_copy_rec_list_start(merge_page, page, page_get_supremum_rec(page), cursor->index, mtr); lock_update_merge_left(merge_page, orig_pred, page); } else { orig_succ = page_rec_get_next( page_get_infimum_rec(merge_page)); page_copy_rec_list_end(merge_page, page, page_get_infimum_rec(page), cursor->index, mtr); lock_update_merge_right(orig_succ, page); } /* We have added new records to merge_page: update its free bits */ ibuf_update_free_bits_if_full(cursor->index, merge_page, UNIV_PAGE_SIZE, ULINT_UNDEFINED); ut_ad(page_validate(merge_page, cursor->index)); /* Free the file page */ btr_page_free(tree, page, mtr); ut_ad(btr_check_node_ptr(tree, merge_page, mtr));} /*****************************************************************Discards a page that is the only page on its level. */staticvoidbtr_discard_only_page_on_level(/*===========================*/ dict_tree_t* tree, /* in: index tree */ page_t* page, /* in: page which is the only on its level */ mtr_t* mtr) /* in: mtr */{ rec_t* node_ptr; page_t* father_page; ulint page_level; 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, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); btr_search_drop_page_hash_index(page); node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); father_page = buf_frame_align(node_ptr); page_level = btr_page_get_level(page, mtr); lock_update_discard(page_get_supremum_rec(father_page), page); btr_page_set_level(father_page, page_level, mtr); /* Free the file page */ btr_page_free(tree, page, mtr); if (buf_frame_get_page_no(father_page) == dict_tree_get_page(tree)) { /* The father is the root page */ btr_page_empty(father_page, mtr); /* We play safe and reset the free bits for the father */ ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), father_page); } else { ut_ad(page_get_n_recs(father_page) == 1); btr_discard_only_page_on_level(tree, father_page, mtr); }} /*****************************************************************Discards a page from a B-tree. This is used to remove the last record froma B-tree page: the whole page must be removed at the same time. This cannotbe used for the root page, which is allowed to be empty. */voidbtr_discard_page(/*=============*/ btr_cur_t* cursor, /* in: cursor on the page to discard: not on the root page */ mtr_t* mtr) /* in: mtr */{ dict_tree_t* tree; ulint space; ulint left_page_no; ulint right_page_no; page_t* merge_page; ibool is_left; page_t* page; rec_t* node_ptr; page = btr_cur_get_page(cursor); tree = btr_cur_get_tree(cursor); ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page)); ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); space = dict_tree_get_space(tree); /* Decide the page which will inherit the locks */ left_page_no = btr_page_get_prev(page, mtr); right_page_no = btr_page_get_next(page, mtr); if (left_page_no != FIL_NULL) { is_left = TRUE; merge_page = btr_page_get(space, left_page_no, RW_X_LATCH, mtr); } else if (right_page_no != FIL_NULL) { is_left = FALSE; merge_page = btr_page_get(space, right_page_no, RW_X_LATCH, mtr); } else { btr_discard_only_page_on_level(tree, page, mtr); return; } ut_a(page_is_comp(merge_page) == page_is_comp(page)); btr_search_drop_page_hash_index(page); if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) { /* We have to mark the leftmost node pointer on the right side page as the predefined minimum record */ node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page)); ut_ad(page_rec_is_user_rec(node_ptr)); btr_set_min_rec_mark(node_ptr, page_is_comp(merge_page), mtr); } btr_node_ptr_delete(tree, page, mtr); /* Remove the page from the level list */ btr_level_list_remove(tree, page, mtr); if (is_left) { lock_update_discard(page_get_supremum_rec(merge_page), page); } else { lock_update_discard(page_rec_get_next( page_get_infimum_rec(merge_page)), page); } /* Free the file page */ btr_page_free(tree, page, mtr); ut_ad(btr_check_node_ptr(tree, merge_page, mtr));} #ifdef UNIV_BTR_PRINT/*****************************************************************Prints size info of a B-tree. */voidbtr_print_size(/*===========*/ dict_tree_t* tree) /* in: index tree */{ page_t* root; fseg_header_t* seg; mtr_t mtr; if (tree->type & DICT_IBUF) { fputs( "Sorry, cannot print info of an ibuf tree: use ibuf functions\n", stderr); return; } mtr_start(&mtr); root = btr_root_get(tree, &mtr); seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -