📄 ibuf0ibuf.c
字号:
dtuple_set_types_binary(tuple, 1); return(tuple);}/*************************************************************************Builds a search tuple used to search buffered inserts for an index page.This is for >= 4.1.x format records. */staticdtuple_t*ibuf_new_search_tuple_build(/*========================*/ /* out, own: search tuple */ ulint space, /* in: space id */ ulint page_no,/* in: index page number */ mem_heap_t* heap) /* in: heap into which to build */{ dtuple_t* tuple; dfield_t* field; byte* buf; ut_a(trx_sys_multiple_tablespace_format); tuple = dtuple_create(heap, 3); /* Store the space id in tuple */ field = dtuple_get_nth_field(tuple, 0); buf = mem_heap_alloc(heap, 4); mach_write_to_4(buf, space); dfield_set_data(field, buf, 4); /* Store the new format record marker byte */ field = dtuple_get_nth_field(tuple, 1); buf = mem_heap_alloc(heap, 1); mach_write_to_1(buf, 0); dfield_set_data(field, buf, 1); /* Store the page number in tuple */ field = dtuple_get_nth_field(tuple, 2); buf = mem_heap_alloc(heap, 4); mach_write_to_4(buf, page_no); dfield_set_data(field, buf, 4); dtuple_set_types_binary(tuple, 3); return(tuple);}/*************************************************************************Checks if there are enough pages in the free list of the ibuf tree that wedare to start a pessimistic insert to the insert buffer. */UNIV_INLINEiboolibuf_data_enough_free_for_insert(/*=============================*/ /* out: TRUE if enough free pages in list */ ibuf_data_t* data) /* in: ibuf data for the space */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&ibuf_mutex));#endif /* UNIV_SYNC_DEBUG */ /* We want a big margin of free pages, because a B-tree can sometimes grow in size also if records are deleted from it, as the node pointers can change, and we must make sure that we are able to delete the inserts buffered for pages that we read to the buffer pool, without any risk of running out of free space in the insert buffer. */ if (data->free_list_len >= data->size / 2 + 3 * data->height) { return(TRUE); } return(FALSE);}/*************************************************************************Checks if there are enough pages in the free list of the ibuf tree that weshould remove them and free to the file space management. */UNIV_INLINEiboolibuf_data_too_much_free(/*====================*/ /* out: TRUE if enough free pages in list */ ibuf_data_t* data) /* in: ibuf data for the space */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&ibuf_mutex));#endif /* UNIV_SYNC_DEBUG */ if (data->free_list_len >= 3 + data->size / 2 + 3 * data->height) { return(TRUE); } return(FALSE);}/*************************************************************************Allocates a new page from the ibuf file segment and adds it to the freelist. */staticulintibuf_add_free_page(/*===============*/ /* out: DB_SUCCESS, or DB_STRONG_FAIL if no space left */ ulint space, /* in: space id */ ibuf_data_t* ibuf_data) /* in: ibuf data for the space */{ mtr_t mtr; page_t* header_page; ulint page_no; page_t* page; page_t* root; page_t* bitmap_page; ut_a(space == 0); mtr_start(&mtr); /* Acquire the fsp latch before the ibuf header, obeying the latching order */ mtr_x_lock(fil_space_get_latch(space), &mtr); header_page = ibuf_header_page_get(space, &mtr); /* Allocate a new page: NOTE that if the page has been a part of a non-clustered index which has subsequently been dropped, then the page may have buffered inserts in the insert buffer, and these should be deleted from there. These get deleted when the page allocation creates the page in buffer. Thus the call below may end up calling the insert buffer routines and, as we yet have no latches to insert buffer tree pages, these routines can run without a risk of a deadlock. This is the reason why we created a special ibuf header page apart from the ibuf tree. */ page_no = fseg_alloc_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP, &mtr); if (page_no == FIL_NULL) { mtr_commit(&mtr); return(DB_STRONG_FAIL); } page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW);#endif /* UNIV_SYNC_DEBUG */ ibuf_enter(); mutex_enter(&ibuf_mutex); root = ibuf_tree_root_get(ibuf_data, space, &mtr); /* Add the page to the free list and update the ibuf size data */ flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr); fil_page_set_type(page, FIL_PAGE_IBUF_FREE_LIST); ibuf_data->seg_size++; ibuf_data->free_list_len++; /* Set the bit indicating that this page is now an ibuf tree page (level 2 page) */ bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF, TRUE, &mtr); mtr_commit(&mtr); mutex_exit(&ibuf_mutex); ibuf_exit(); return(DB_SUCCESS);}/*************************************************************************Removes a page from the free list and frees it to the fsp system. */staticvoidibuf_remove_free_page(/*==================*/ ulint space, /* in: space id */ ibuf_data_t* ibuf_data) /* in: ibuf data for the space */{ mtr_t mtr; mtr_t mtr2; page_t* header_page; ulint page_no; page_t* page; page_t* root; page_t* bitmap_page; ut_a(space == 0); mtr_start(&mtr); /* Acquire the fsp latch before the ibuf header, obeying the latching order */ mtr_x_lock(fil_space_get_latch(space), &mtr); header_page = ibuf_header_page_get(space, &mtr); /* Prevent pessimistic inserts to insert buffer trees for a while */ mutex_enter(&ibuf_pessimistic_insert_mutex); ibuf_enter(); mutex_enter(&ibuf_mutex); if (!ibuf_data_too_much_free(ibuf_data)) { mutex_exit(&ibuf_mutex); ibuf_exit(); mutex_exit(&ibuf_pessimistic_insert_mutex); mtr_commit(&mtr); return; } mtr_start(&mtr2); root = ibuf_tree_root_get(ibuf_data, space, &mtr2); page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, &mtr2) .page; /* NOTE that we must release the latch on the ibuf tree root because in fseg_free_page we access level 1 pages, and the root is a level 2 page. */ mtr_commit(&mtr2); mutex_exit(&ibuf_mutex); ibuf_exit(); /* Since pessimistic inserts were prevented, we know that the page is still in the free list. NOTE that also deletes may take pages from the free list, but they take them from the start, and the free list was so long that they cannot have taken the last page from it. */ fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, space, page_no, &mtr);#ifdef UNIV_DEBUG_FILE_ACCESSES buf_page_reset_file_page_was_freed(space, page_no);#endif ibuf_enter(); mutex_enter(&ibuf_mutex); root = ibuf_tree_root_get(ibuf_data, space, &mtr); ut_ad(page_no == flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, &mtr) .page); page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_TREE_NODE);#endif /* UNIV_SYNC_DEBUG */ /* Remove the page from the free list and update the ibuf size data */ flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr); ibuf_data->seg_size--; ibuf_data->free_list_len--; mutex_exit(&ibuf_pessimistic_insert_mutex); /* Set the bit indicating that this page is no more an ibuf tree page (level 2 page) */ bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF, FALSE, &mtr);#ifdef UNIV_DEBUG_FILE_ACCESSES buf_page_set_file_page_was_freed(space, page_no);#endif mtr_commit(&mtr); mutex_exit(&ibuf_mutex); ibuf_exit();}/***************************************************************************Frees excess pages from the ibuf free list. This function is called when an OSthread calls fsp services to allocate a new file segment, or a new page to afile segment, and the thread did not own the fsp latch before this call. */ voidibuf_free_excess_pages(/*===================*/ ulint space) /* in: space id */{ ibuf_data_t* ibuf_data; ulint i; if (space != 0) { fprintf(stderr,"InnoDB: Error: calling ibuf_free_excess_pages for space %lu\n", (ulong) space); return; }#ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(fil_space_get_latch(space), RW_LOCK_EX));#endif /* UNIV_SYNC_DEBUG */ ut_ad(rw_lock_get_x_lock_count(fil_space_get_latch(space)) == 1); ut_ad(!ibuf_inside()); /* NOTE: We require that the thread did not own the latch before, because then we know that we can obey the correct latching order for ibuf latches */ ibuf_data = fil_space_get_ibuf_data(space); if (ibuf_data == NULL) { /* Not yet initialized */#ifdef UNIV_DEBUG /*fprintf(stderr, "Ibuf for space %lu not yet initialized\n", space); */#endif return; } /* Free at most a few pages at a time, so that we do not delay the requested service too much */ for (i = 0; i < 4; i++) { mutex_enter(&ibuf_mutex); if (!ibuf_data_too_much_free(ibuf_data)) { mutex_exit(&ibuf_mutex); return; } mutex_exit(&ibuf_mutex); ibuf_remove_free_page(space, ibuf_data); }}/*************************************************************************Reads page numbers from a leaf in an ibuf tree. */staticulintibuf_get_merge_page_nos(/*====================*/ /* out: a lower limit for the combined volume of records which will be merged */ ibool contract,/* in: TRUE if this function is called to contract the tree, FALSE if this is called when a single page becomes full and we look if it pays to read also nearby pages */ rec_t* rec, /* in: record from which we read up and down in the chain of records */ ulint* space_ids,/* in/out: space id's of the pages */ ib_longlong* space_versions,/* in/out: tablespace version timestamps; used to prevent reading in old pages after DISCARD + IMPORT tablespace */ ulint* page_nos,/* in/out: buffer for at least IBUF_MAX_N_PAGES_MERGED many page numbers; the page numbers are in an ascending order */ ulint* n_stored)/* out: number of page numbers stored to page_nos in this function */{ ulint prev_page_no; ulint prev_space_id; ulint first_page_no; ulint first_space_id; ulint rec_page_no; ulint rec_space_id; ulint sum_volumes; ulint volume_for_page; ulint rec_volume; ulint limit; ulint n_pages; *n_stored = 0; limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4); if (page_rec_is_supremum(rec)) { rec = page_rec_get_prev(rec); } if (page_rec_is_infimum(rec)) { rec = page_rec_get_next(rec); } if (page_rec_is_supremum(rec)) { return(0); } first_page_no = ibuf_rec_get_page_no(rec); first_space_id = ibuf_rec_get_space(rec); n_pages = 0; prev_page_no = 0; prev_space_id = 0; /* Go backwards from the first rec until we reach the border of the 'merge area', or the page start or the limit of storeable pages is reached */ while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) { rec_page_no = ibuf_rec_get_page_no(rec); rec_space_id = ibuf_rec_get_space(rec); if (rec_space_id != first_space_id || rec_page_no / IBUF_MERGE_AREA != first_page_no / IBUF_MERGE_AREA) { break; } if (rec_page_no != prev_page_no || rec_space_id != prev_space_id) { n_pages++; } prev_page_no = rec_page_no; prev_space_id = rec_space_id; rec = page_rec_get_prev(rec); } rec = page_rec_get_next(rec); /* At the loop start there is no prev page; we mark this with a pair of space id, page no (0, 0) for which there can never be entries in the insert buffer */ prev_page_no = 0; prev_space_id = 0; sum_volumes = 0; volume_for_page = 0; while (*n_stored < limit) { if (page_rec_is_supremum(rec)) { /* When no more records available, mark this with another 'impossible' pair of space id, page no */ rec_page_no = 1; rec_space_id = 0; } else { rec_page_no = ibuf_rec_get_page_no(rec); rec_space_id = ibuf_rec_get_space(rec); ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO); }#ifdef UNIV_IBUF_DEBUG ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED);#endif if ((rec_space_id != prev_space_id || rec_page_no != prev_page_no) && (prev_space_id != 0 || prev_page_no != 0)) { if ((prev_page_no == first_page_no && prev_space_id == first_space_id) || contract || (volume_for_page > ((IBUF_MERGE_THRESHOLD - 1) * 4 * UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -