📄 btr0btr.c
字号:
} else { seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; } space = buf_frame_get_space_id(page); page_no = buf_frame_get_page_no(page); fseg_free_page(seg_header, space, page_no, mtr);} /******************************************************************Frees a file page used in an index tree. NOTE: cannot free field externalstorage pages because the page must contain info on its level. */voidbtr_page_free(/*==========*/ dict_tree_t* tree, /* in: index tree */ page_t* page, /* in: page to be freed, x-latched */ mtr_t* mtr) /* in: mtr */{ ulint level; ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); level = btr_page_get_level(page, mtr); btr_page_free_low(tree, page, level, mtr);} /******************************************************************Sets the child node file address in a node pointer. */UNIV_INLINEvoidbtr_node_ptr_set_child_page_no(/*===========================*/ rec_t* rec, /* in: node pointer record */ const ulint* offsets,/* in: array returned by rec_get_offsets() */ ulint page_no,/* in: child node address */ mtr_t* mtr) /* in: mtr */{ byte* field; ulint len; ut_ad(rec_offs_validate(rec, NULL, offsets)); ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr)); ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec)); /* The child address is in the last field */ field = rec_get_nth_field(rec, offsets, rec_offs_n_fields(offsets) - 1, &len); ut_ad(len == 4); mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);}/****************************************************************Returns the child page of a node pointer and x-latches it. */staticpage_t*btr_node_ptr_get_child(/*===================*/ /* out: child page, x-latched */ rec_t* node_ptr,/* in: node pointer */ const ulint* offsets,/* in: array returned by rec_get_offsets() */ mtr_t* mtr) /* in: mtr */{ ulint page_no; ulint space; page_t* page; ut_ad(rec_offs_validate(node_ptr, NULL, offsets)); space = buf_frame_get_space_id(node_ptr); page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); page = btr_page_get(space, page_no, RW_X_LATCH, mtr); return(page);}/****************************************************************Returns the upper level node pointer to a page. It is assumed that mtr holdsan x-latch on the tree. */staticrec_t*btr_page_get_father_for_rec(/*========================*/ /* out: pointer to node pointer record, its page x-latched */ dict_tree_t* tree, /* in: index tree */ page_t* page, /* in: page: must contain at least one user record */ rec_t* user_rec,/* in: user_record on page */ mtr_t* mtr) /* in: mtr */{ mem_heap_t* heap; dtuple_t* tuple; btr_cur_t cursor; rec_t* node_ptr; dict_index_t* index; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK)); ut_a(page_rec_is_user_rec(user_rec)); ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page)); heap = mem_heap_create(100); tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap, btr_page_get_level(page, mtr)); index = UT_LIST_GET_FIRST(tree->tree_indexes); /* In the following, we choose just any index from the tree as the first parameter for btr_cur_search_to_nth_level. */ btr_cur_search_to_nth_level(index, btr_page_get_level(page, mtr) + 1, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE, &cursor, 0, mtr); node_ptr = btr_cur_get_rec(&cursor); offsets = rec_get_offsets(node_ptr, index, offsets, ULINT_UNDEFINED, &heap); if (btr_node_ptr_get_child_page_no(node_ptr, offsets) != buf_frame_get_page_no(page)) { rec_t* print_rec; fputs("InnoDB: Dump of the child page:\n", stderr); buf_page_print(buf_frame_align(page)); fputs("InnoDB: Dump of the parent page:\n", stderr); buf_page_print(buf_frame_align(node_ptr)); fputs("InnoDB: Corruption of an index tree: table ", stderr); ut_print_name(stderr, NULL, index->table_name); fputs(", index ", stderr); ut_print_name(stderr, NULL, index->name); fprintf(stderr, ",\n""InnoDB: father ptr page no %lu, child page no %lu\n", (ulong) btr_node_ptr_get_child_page_no(node_ptr, offsets), (ulong) buf_frame_get_page_no(page)); print_rec = page_rec_get_next(page_get_infimum_rec(page)); offsets = rec_get_offsets(print_rec, index, offsets, ULINT_UNDEFINED, &heap); page_rec_print(print_rec, offsets); offsets = rec_get_offsets(node_ptr, index, offsets, ULINT_UNDEFINED, &heap); page_rec_print(node_ptr, offsets); fputs("InnoDB: You should dump + drop + reimport the table to fix the\n""InnoDB: corruption. If the crash happens at the database startup, see\n""InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html about\n""InnoDB: forcing recovery. Then dump + drop + reimport.\n", stderr); } ut_a(btr_node_ptr_get_child_page_no(node_ptr, offsets) == buf_frame_get_page_no(page)); mem_heap_free(heap); return(node_ptr);}/****************************************************************Returns the upper level node pointer to a page. It is assumed thatmtr holds an x-latch on the tree. */staticrec_t*btr_page_get_father_node_ptr(/*=========================*/ /* out: pointer to node pointer record */ dict_tree_t* tree, /* in: index tree */ page_t* page, /* in: page: must contain at least one user record */ mtr_t* mtr) /* in: mtr */{ return(btr_page_get_father_for_rec(tree, page, page_rec_get_next(page_get_infimum_rec(page)), mtr));}/****************************************************************Creates the root node for a new index tree. */ulintbtr_create(/*=======*/ /* out: page number of the created root, FIL_NULL if did not succeed */ ulint type, /* in: type of the index */ ulint space, /* in: space where created */ dulint index_id,/* in: index id */ ulint comp, /* in: nonzero=compact page format */ mtr_t* mtr) /* in: mini-transaction handle */{ ulint page_no; buf_frame_t* ibuf_hdr_frame; buf_frame_t* frame; page_t* page; /* Create the two new segments (one, in the case of an ibuf tree) for the index tree; the segment headers are put on the allocated root page (for an ibuf tree, not in the root, but on a separate ibuf header page) */ if (type & DICT_IBUF) { /* Allocate first the ibuf header page */ ibuf_hdr_frame = fseg_create(space, 0, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(ibuf_hdr_frame, SYNC_TREE_NODE_NEW);#endif /* UNIV_SYNC_DEBUG */ ut_ad(buf_frame_get_page_no(ibuf_hdr_frame) == IBUF_HEADER_PAGE_NO); /* Allocate then the next page to the segment: it will be the tree root page */ page_no = fseg_alloc_free_page( ibuf_hdr_frame + IBUF_HEADER + IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO, FSP_UP, mtr); ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); frame = buf_page_get(space, page_no, RW_X_LATCH, mtr); } else { frame = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); } if (frame == NULL) { return(FIL_NULL); } page_no = buf_frame_get_page_no(frame); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);#endif /* UNIV_SYNC_DEBUG */ if (type & DICT_IBUF) { /* It is an insert buffer tree: initialize the free list */ ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr); } else { /* It is a non-ibuf tree: create a file segment for leaf pages */ fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr); /* The fseg create acquires a second latch on the page, therefore we must declare it: */#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);#endif /* UNIV_SYNC_DEBUG */ } /* Create a new index page on the the allocated segment page */ page = page_create(frame, mtr, comp); buf_block_align(page)->check_index_page_at_flush = TRUE; /* Set the index id of the page */ btr_page_set_index_id(page, index_id, mtr); /* Set the level of the new index page */ btr_page_set_level(page, 0, mtr); /* Set the next node and previous node fields */ btr_page_set_next(page, FIL_NULL, mtr); btr_page_set_prev(page, FIL_NULL, mtr); /* We reset the free bits for the page to allow creation of several trees in the same mtr, otherwise the latch on a bitmap page would prevent it because of the latching order */ ibuf_reset_free_bits_with_type(type, page); /* In the following assertion we test that two records of maximum allowed size fit on the root page: this fact is needed to ensure correctness of split algorithms */ ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE); return(page_no);}/****************************************************************Frees a B-tree except the root page, which MUST be freed after thisby calling btr_free_root. */voidbtr_free_but_not_root(/*==================*/ ulint space, /* in: space where created */ ulint root_page_no) /* in: root page number */{ ibool finished; page_t* root; mtr_t mtr;leaf_loop: mtr_start(&mtr); root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr); /* NOTE: page hash indexes are dropped when a page is freed inside fsp0fsp. */ finished = fseg_free_step( root + PAGE_HEADER + PAGE_BTR_SEG_LEAF, &mtr); mtr_commit(&mtr); if (!finished) { goto leaf_loop; }top_loop: mtr_start(&mtr); root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr); finished = fseg_free_step_not_header( root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr); mtr_commit(&mtr); if (!finished) { goto top_loop; } }/****************************************************************Frees the B-tree root page. Other tree MUST already have been freed. */voidbtr_free_root(/*==========*/ ulint space, /* in: space where created */ ulint root_page_no, /* in: root page number */ mtr_t* mtr) /* in: a mini-transaction which has already been started */{ ibool finished; page_t* root; root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr); btr_search_drop_page_hash_index(root); top_loop: finished = fseg_free_step( root + PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); if (!finished) { goto top_loop; } }/*****************************************************************Reorganizes an index page. */staticvoidbtr_page_reorganize_low(/*====================*/ ibool recovery,/* in: TRUE if called in recovery: locks should not be updated, i.e., there cannot exist locks on the page, and a hash index should not be dropped: it cannot exist */ page_t* page, /* in: page to be reorganized */ dict_index_t* index, /* in: record descriptor */ mtr_t* mtr) /* in: mtr */{ page_t* new_page; ulint log_mode; ulint data_size1; ulint data_size2; ulint max_ins_size1; ulint max_ins_size2; ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); ut_ad(!!page_is_comp(page) == index->table->comp); data_size1 = page_get_data_size(page); max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1); /* Write the log record */ mlog_open_and_write_index(mtr, page, index, page_is_comp(page) ? MLOG_COMP_PAGE_REORGANIZE : MLOG_PAGE_REORGANIZE, 0); /* Turn logging off */ log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); new_page = buf_frame_alloc(); /* Copy the old page to temporary space */ buf_frame_copy(new_page, page); if (!recovery) { btr_search_drop_page_hash_index(page); } /* Recreate the page: note that global data on page (possible segment headers, next page-field, etc.) is preserved intact */ page_create(page, mtr, page_is_comp(page)); buf_block_align(page)->check_index_page_at_flush = TRUE; /* Copy the records from the temporary space to the recreated page; do not copy the lock bits yet */ page_copy_rec_list_end_no_locks(page, new_page, page_get_infimum_rec(new_page), index, mtr); /* Copy max trx id to recreated page */ page_set_max_trx_id(page, page_get_max_trx_id(new_page)); if (!recovery) { /* Update the record lock bitmaps */ lock_move_reorganize_page(page, new_page); } data_size2 = page_get_data_size(page); max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1); if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) { buf_page_print(page); buf_page_print(new_page); fprintf(stderr,"InnoDB: Error: page old data size %lu new data size %lu\n""InnoDB: Error: page old max ins size %lu new max ins size %lu\n""InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", (unsigned long) data_size1, (unsigned long) data_size2, (unsigned long) max_ins_size1, (unsigned long) max_ins_size2); } buf_frame_free(new_page); /* Restore logging mode */ mtr_set_log_mode(mtr, log_mode);}/*****************************************************************Reorganizes an index page. */voidbtr_page_reorganize(/*================*/ page_t* page, /* in: page to be reorganized */ dict_index_t* index, /* in: record descriptor */ mtr_t* mtr) /* in: mtr */{ btr_page_reorganize_low(FALSE, page, index, mtr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -