📄 fsp0fsp.c
字号:
fseg_get_nth_frag_page_no(/*======================*/ /* out: page number, FIL_NULL if not in use */ fseg_inode_t* inode, /* in: segment inode */ ulint n, /* in: slot index */ mtr_t* mtr __attribute__((unused))) /* in: mtr handle */{ ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains(mtr, buf_block_align(inode), MTR_MEMO_PAGE_X_FIX)); return(mach_read_from_4(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE));}/**************************************************************************Sets the page number in the nth fragment page slot. */UNIV_INLINEvoidfseg_set_nth_frag_page_no(/*======================*/ fseg_inode_t* inode, /* in: segment inode */ ulint n, /* in: slot index */ ulint page_no,/* in: page number to set */ mtr_t* mtr) /* in: mtr handle */{ ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains(mtr, buf_block_align(inode), MTR_MEMO_PAGE_X_FIX)); mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE, page_no, MLOG_4BYTES, mtr);}/**************************************************************************Finds a fragment page slot which is free. */staticulintfseg_find_free_frag_page_slot(/*==========================*/ /* out: slot index; ULINT_UNDEFINED if none found */ fseg_inode_t* inode, /* in: segment inode */ mtr_t* mtr) /* in: mtr handle */{ ulint i; ulint page_no; ut_ad(inode && mtr); for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) { page_no = fseg_get_nth_frag_page_no(inode, i, mtr); if (page_no == FIL_NULL) { return(i); } } return(ULINT_UNDEFINED);}/**************************************************************************Finds a fragment page slot which is used and last in the array. */staticulintfseg_find_last_used_frag_page_slot(/*===============================*/ /* out: slot index; ULINT_UNDEFINED if none found */ fseg_inode_t* inode, /* in: segment inode */ mtr_t* mtr) /* in: mtr handle */{ ulint i; ulint page_no; ut_ad(inode && mtr); for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) { page_no = fseg_get_nth_frag_page_no(inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr); if (page_no != FIL_NULL) { return(FSEG_FRAG_ARR_N_SLOTS - i - 1); } } return(ULINT_UNDEFINED);}/**************************************************************************Calculates reserved fragment page slots. */staticulintfseg_get_n_frag_pages(/*==================*/ /* out: number of fragment pages */ fseg_inode_t* inode, /* in: segment inode */ mtr_t* mtr) /* in: mtr handle */{ ulint i; ulint count = 0; ut_ad(inode && mtr); for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) { if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) { count++; } } return(count);}/**************************************************************************Creates a new segment. */page_t*fseg_create_general(/*================*/ /* out: the page where the segment header is placed, x-latched, NULL if could not create segment because of lack of space */ ulint space, /* in: space id */ ulint page, /* in: page where the segment header is placed: if this is != 0, the page must belong to another segment, if this is 0, a new page will be allocated and it will belong to the created segment */ ulint byte_offset, /* in: byte offset of the created segment header on the page */ ibool has_done_reservation, /* in: TRUE if the caller has already done the reservation for the pages with fsp_reserve_free_extents (at least 2 extents: one for the inode and the other for the segment) then there is no need to do the check for this individual operation */ mtr_t* mtr) /* in: mtr */{ fsp_header_t* space_header; fseg_inode_t* inode; dulint seg_id; fseg_header_t* header = 0; /* remove warning */ rw_lock_t* latch; ibool success; ulint n_reserved; page_t* ret = NULL; ulint i; ut_ad(mtr); if (page != 0) { header = byte_offset + buf_page_get(space, page, RW_X_LATCH, mtr); } #ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&kernel_mutex) || mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK));#endif /* UNIV_SYNC_DEBUG */ latch = fil_space_get_latch(space); mtr_x_lock(latch, mtr); if (rw_lock_get_x_lock_count(latch) == 1) { /* This thread did not own the latch before this call: free excess pages from the insert buffer free list */ if (space == 0) { ibuf_free_excess_pages(space); } } if (!has_done_reservation) { success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_NORMAL, mtr); if (!success) { return(NULL); } } space_header = fsp_get_space_header(space, mtr); inode = fsp_alloc_seg_inode(space_header, mtr); if (inode == NULL) { goto funct_exit; } /* Read the next segment id from space header and increment the value in space header */ seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, mtr); mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1), mtr); mlog_write_dulint(inode + FSEG_ID, seg_id, mtr); mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr); flst_init(inode + FSEG_FREE, mtr); flst_init(inode + FSEG_NOT_FULL, mtr); flst_init(inode + FSEG_FULL, mtr); mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE, MLOG_4BYTES, mtr); for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) { fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr); } if (page == 0) { page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr); if (page == FIL_NULL) { fsp_free_seg_inode(space, inode, mtr); goto funct_exit; } header = byte_offset + buf_page_get(space, page, RW_X_LATCH, mtr); } mlog_write_ulint(header + FSEG_HDR_OFFSET, inode - buf_frame_align(inode), MLOG_2BYTES, mtr); mlog_write_ulint(header + FSEG_HDR_PAGE_NO, buf_frame_get_page_no(inode), MLOG_4BYTES, mtr); mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr); ret = buf_frame_align(header);funct_exit: if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } return(ret);}/**************************************************************************Creates a new segment. */page_t*fseg_create(/*========*/ /* out: the page where the segment header is placed, x-latched, NULL if could not create segment because of lack of space */ ulint space, /* in: space id */ ulint page, /* in: page where the segment header is placed: if this is != 0, the page must belong to another segment, if this is 0, a new page will be allocated and it will belong to the created segment */ ulint byte_offset, /* in: byte offset of the created segment header on the page */ mtr_t* mtr) /* in: mtr */{ return(fseg_create_general(space, page, byte_offset, FALSE, mtr));}/**************************************************************************Calculates the number of pages reserved by a segment, and how many pages arecurrently used. */staticulintfseg_n_reserved_pages_low(/*======================*/ /* out: number of reserved pages */ fseg_inode_t* inode, /* in: segment inode */ ulint* used, /* out: number of pages used (<= reserved) */ mtr_t* mtr) /* in: mtr handle */{ ulint ret; ut_ad(inode && used && mtr); ut_ad(mtr_memo_contains(mtr, buf_block_align(inode), MTR_MEMO_PAGE_X_FIX)); *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr) + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr) + fseg_get_n_frag_pages(inode, mtr); ret = fseg_get_n_frag_pages(inode, mtr) + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr) + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr) + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr); return(ret);}/**************************************************************************Calculates the number of pages reserved by a segment, and how many pages arecurrently used. */ulintfseg_n_reserved_pages(/*==================*/ /* out: number of reserved pages */ fseg_header_t* header, /* in: segment header */ ulint* used, /* out: number of pages used (<= reserved) */ mtr_t* mtr) /* in: mtr handle */{ ulint ret; fseg_inode_t* inode; ulint space; space = buf_frame_get_space_id(header);#ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&kernel_mutex) || mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK));#endif /* UNIV_SYNC_DEBUG */ mtr_x_lock(fil_space_get_latch(space), mtr); inode = fseg_inode_get(header, mtr); ret = fseg_n_reserved_pages_low(inode, used, mtr); return(ret);}/*************************************************************************Tries to fill the free list of a segment with consecutive free extents.This happens if the segment is big enough to allow extents in the free list,the free list is empty, and the extents can be allocated consecutively fromthe hint onward. */staticvoidfseg_fill_free_list(/*================*/ fseg_inode_t* inode, /* in: segment inode */ ulint space, /* in: space id */ ulint hint, /* in: hint which extent would be good as the first extent */ mtr_t* mtr) /* in: mtr */{ xdes_t* descr; ulint i; dulint seg_id; ulint reserved; ulint used; ut_ad(inode && mtr); reserved = fseg_n_reserved_pages_low(inode, &used, mtr); if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) { /* The segment is too small to allow extents in free list */ return; } if (flst_get_len(inode + FSEG_FREE, mtr) > 0) { /* Free list is not empty */ return; } for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) { descr = xdes_get_descriptor(space, hint, mtr); if ((descr == NULL) || (XDES_FREE != xdes_get_state(descr, mtr))) { /* We cannot allocate the desired extent: stop */ return; } descr = fsp_alloc_free_extent(space, hint, mtr); xdes_set_state(descr, XDES_FSEG, mtr); seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); mlog_write_dulint(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); hint += FSP_EXTENT_SIZE; }}/*************************************************************************Allocates a free extent for the segment: looks first in the free list of thesegment, then tries to allocate from the space free list. NOTE that the extentreturned still resides in the segment free list, it is not yet taken off it! */staticxdes_t*fseg_alloc_free_extent(/*===================*/ /* out: allocated extent, still placed in the segment free list, NULL if could not be allocated */ fseg_inode_t* inode, /* in: segment inode */ ulint space, /* in: space id */ mtr_t* mtr) /* in: mtr */{ xdes_t* descr; dulint seg_id; fil_addr_t first; if (flst_get_len(inode + FSEG_FREE, mtr) > 0) { /* Segment free list is not empty, allocate from it */ first = flst_get_first(inode + FSEG_FREE, mtr); descr = xdes_lst_get_descriptor(space, first, mtr); } else { /* Segment free list was empty, allocate from space */ descr = fsp_alloc_free_extent(space, 0, mtr); if (descr == NULL) { return(NULL); } seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); xdes_set_state(descr, XDES_FSEG, mtr); mlog_write_dulint(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); /* Try to fill the segment free list */ fseg_fill_free_list(inode, space, xdes_get_offset(descr) + FSP_EXTENT_SIZE, mtr); } return(descr);}/**************************************************************************Allocates a single free page from a segment. This function implementsthe intelligent allocation strategy which tries to minimize file spacefragmentation. */staticulintfseg_alloc_free_page_low(/*=====================*/ /* out: the allocated page number, FIL_NULL if no page could be allocated */ ulint space, /* in: space */ fseg_inode_t* seg_inode, /* in: segment inode */ ulint hint, /* in: hint of which page would be desirable */ byte direction, /* in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ mtr_t* mtr) /* in: mtr handle */{ fsp_header_t* space_header; ulint space_size; dulint seg_id; ulint used; ulint reserved; xdes_t* descr; /* extent of the hinted page */ ulint ret_page; /* the allocated pag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -