diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 93ad4b671c80c..89dee3b1edecb 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -177,19 +177,18 @@ we allocate pages for the non-leaf levels of the tree. */ /** Check a file segment header within a B-tree root page. -@param offset file segment header offset +@param fseg file segment header @param block B-tree root page @param space tablespace @return whether the segment header is valid */ -static bool btr_root_fseg_validate(ulint offset, +static bool btr_root_fseg_validate(const byte *fseg, const buf_block_t &block, const fil_space_t &space) { ut_ad(block.page.id().space() == space.id); - const uint16_t hdr= mach_read_from_2(offset + FSEG_HDR_OFFSET + - block.page.frame); + const uint16_t hdr= mach_read_from_2(fseg + FSEG_HDR_OFFSET); if (FIL_PAGE_DATA <= hdr && hdr <= srv_page_size - FIL_PAGE_DATA_END && - mach_read_from_4(block.page.frame + offset + FSEG_HDR_SPACE) == space.id) + mach_read_from_4(fseg + FSEG_HDR_SPACE) == space.id) return true; sql_print_error("InnoDB: Index root page " UINT32PF " in %s is corrupted " "at " ULINTPF, @@ -234,11 +233,11 @@ buf_block_t *btr_block_get(const dict_index_t &index, if (UNIV_LIKELY(block != nullptr)) { - if (!!page_is_comp(block->page.frame) != index.table->not_redundant() || - btr_page_get_index_id(block->page.frame) != index.id || - !fil_page_index_page_check(block->page.frame) || - index.is_spatial() != - (fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE)) + const page_t *page= block->page.frame; + if (!!page_is_comp(page) != index.table->not_redundant() || + btr_page_get_index_id(page) != index.id || + !fil_page_index_page_check(page) || + index.is_spatial() != (fil_page_get_type(page) == FIL_PAGE_RTREE)) { *err= DB_PAGE_CORRUPTED; block= nullptr; @@ -287,20 +286,20 @@ btr_root_block_get( if (UNIV_LIKELY(block != nullptr)) { - if (!!page_is_comp(block->page.frame) != - index->table->not_redundant() || - btr_page_get_index_id(block->page.frame) != index->id || - !fil_page_index_page_check(block->page.frame) || - index->is_spatial() != - (fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE)) + const page_t *page= block->page.frame; + + if (!!page_is_comp(page) != index->table->not_redundant() || + btr_page_get_index_id(page) != index->id || + !fil_page_index_page_check(page) || + index->is_spatial() != (fil_page_get_type(page) == FIL_PAGE_RTREE)) { *err= DB_PAGE_CORRUPTED; block= nullptr; } else if (index->is_ibuf()); - else if (!btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF, + else if (!btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + page, *block, *index->table->space) || - !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP, + !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + page, *block, *index->table->space)) { *err= DB_CORRUPTION; @@ -394,7 +393,7 @@ btr_root_adjust_on_import( goto func_exit; } - page = buf_block_get_frame(block); + page = block->page.frame; page_zip = buf_block_get_page_zip(block); if (!fil_page_index_page_check(page) || page_has_siblings(page)) { @@ -462,8 +461,8 @@ btr_page_create( mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); - byte *index_id= my_assume_aligned<2>(PAGE_HEADER + PAGE_INDEX_ID + - block->page.frame); + page_t *page= block->page.frame; + byte *index_id= my_assume_aligned<2>(PAGE_HEADER + PAGE_INDEX_ID + page); if (UNIV_LIKELY_NULL(page_zip)) { @@ -477,17 +476,15 @@ btr_page_create( { static_assert(((FIL_PAGE_INDEX & 0xff00) | byte(FIL_PAGE_RTREE)) == FIL_PAGE_RTREE, "compatibility"); - mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->page.frame, - byte(FIL_PAGE_RTREE)); - if (mach_read_from_8(block->page.frame + FIL_RTREE_SPLIT_SEQ_NUM)) - mtr->memset(block, FIL_RTREE_SPLIT_SEQ_NUM, 8, 0); + mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + page, byte(FIL_PAGE_RTREE)); + if (mach_read_from_8(page + FIL_RTREE_SPLIT_SEQ_NUM)) + mtr->memset(block, page + FIL_RTREE_SPLIT_SEQ_NUM, 8, 0); } /* Set the level of the new index page */ mtr->write<2,mtr_t::MAYBE_NOP>(*block, my_assume_aligned<2>(PAGE_HEADER + - PAGE_LEVEL + - block->page.frame), - level); + PAGE_LEVEL + page), + level); mtr->write<8,mtr_t::MAYBE_NOP>(*block, index_id, index->id); } } @@ -551,18 +548,21 @@ btr_page_alloc_for_ibuf( buf_block_t *root= btr_get_latched_root(*index, mtr); if (UNIV_UNLIKELY(!root)) return root; + page_t *r= root->page.frame; buf_block_t *new_block= buf_page_get_gen(page_id_t(IBUF_SPACE_ID, mach_read_from_4(PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + FLST_FIRST + FIL_ADDR_PAGE + - root->page.frame)), + r)), 0, RW_X_LATCH, nullptr, BUF_GET, mtr, err); if (new_block) { buf_page_make_young_if_needed(&new_block->page); - *err= flst_remove(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, new_block, - PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, + *err= flst_remove(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + r, + new_block, + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE + + new_block->page.frame, fil_system.sys_space->free_limit, mtr); } ut_d(if (*err == DB_SUCCESS) @@ -666,9 +666,10 @@ btr_page_free_for_ibuf( ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); buf_block_t *root= btr_get_latched_root(*index, mtr); dberr_t err= - flst_add_first(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, - block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, - fil_system.sys_space->free_limit, mtr); + flst_add_first(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + + root->page.frame, + block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE + + block->page.frame, fil_system.sys_space->free_limit, mtr); ut_d(if (err == DB_SUCCESS) flst_validate(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr)); return err; @@ -803,7 +804,7 @@ btr_page_get_father_node_ptr_for_validate( const auto level = btr_page_get_level(btr_cur_get_page(cursor)); const rec_t* user_rec = btr_cur_get_rec(cursor); - ut_a(page_rec_is_user_rec(user_rec)); + ut_ad(page_rec_is_user_rec(btr_cur_get_page(cursor), user_rec)); if (btr_cur_search_to_nth_level(level + 1, dict_index_build_node_ptr(index, @@ -843,7 +844,7 @@ static rec_offs *btr_page_get_parent(rec_offs *offsets, mem_heap_t *heap, ut_ad(index->page != page_no); uint32_t p= index->page; - auto level= btr_page_get_level(cursor->block()->page.frame); + auto level= btr_page_get_level(btr_cur_get_page(cursor)); const dtuple_t *tuple= dict_index_build_node_ptr(index, btr_cur_get_rec(cursor), 0, heap, level); level++; @@ -901,8 +902,7 @@ btr_page_get_father_block( btr_cur_t* cursor) /*!< out: cursor on node pointer record, its page x-latched */ { - rec_t *rec= - page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame)); + rec_t *rec= page_rec_get_first(cursor->block()->page.frame); if (UNIV_UNLIKELY(!rec)) return nullptr; cursor->page_cur.rec= rec; @@ -915,8 +915,7 @@ btr_page_get_father_block( @return whether the cursor was successfully positioned */ bool btr_page_get_father(mtr_t* mtr, btr_cur_t* cursor) { - rec_t *rec= - page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame)); + rec_t *rec= page_rec_get_first(cursor->block()->page.frame); if (UNIV_UNLIKELY(!rec)) return false; cursor->page_cur.rec= rec; @@ -934,10 +933,11 @@ constexpr index_id_t BTR_FREED_INDEX_ID = 0; /** Free a B-tree root page. btr_free_but_not_root() must already have been called. @param block index root page +@param page index root page frame @param space tablespace @param mtr mini-transaction */ -static void btr_free_root(buf_block_t *block, const fil_space_t &space, - mtr_t *mtr) +static void btr_free_root(buf_block_t *block, page_t *page, + const fil_space_t &space, mtr_t *mtr) { ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); @@ -945,12 +945,12 @@ static void btr_free_root(buf_block_t *block, const fil_space_t &space, btr_search_drop_page_hash_index(block, false); - if (btr_root_fseg_validate(PAGE_HEADER + PAGE_BTR_SEG_TOP, *block, space)) + if (btr_root_fseg_validate(PAGE_HEADER + PAGE_BTR_SEG_TOP + page, *block, + space)) { /* Free the entire segment in small steps. */ ut_d(mtr->freeing_tree()); - while (!fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_TOP + - block->page.frame, mtr)); + while (!fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_TOP + page, mtr)); } } @@ -972,29 +972,34 @@ buf_block_t *btr_free_root_check(const page_id_t page_id, ulint zip_size, buf_block_t *block= buf_page_get_gen(page_id, zip_size, RW_X_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, mtr); - if (!block); - else if (fil_page_index_page_check(block->page.frame) && - index_id == btr_page_get_index_id(block->page.frame)) - /* This should be a root page. It should not be possible to - reassign the same index_id for some other index in the - tablespace. */ - ut_ad(!page_has_siblings(block->page.frame)); - else - block= nullptr; + if (block) + { + const page_t *page= block->page.frame; + if (fil_page_index_page_check(page) && + index_id == btr_page_get_index_id(page)) + /* This should be a root page. It should not be possible to + reassign the same index_id for some other index in the + tablespace. */ + ut_ad(!page_has_siblings(page)); + else + block= nullptr; + } return block; } /** Initialize the root page of the b-tree @param[in,out] block root block +@param[in,out] page root page frame @param[in] index_id index id @param[in] index index of root page @param[in,out] mtr mini-transaction */ -static void btr_root_page_init(buf_block_t *block, index_id_t index_id, +static void btr_root_page_init(buf_block_t *block, page_t *page, + index_id_t index_id, dict_index_t *index, mtr_t *mtr) { - constexpr uint16_t field= PAGE_HEADER + PAGE_INDEX_ID; - byte *page_index_id= my_assume_aligned<2>(field + block->page.frame); + byte *page_index_id= + my_assume_aligned<2>(PAGE_HEADER + PAGE_INDEX_ID + page); /* Create a new index page on the allocated segment page */ if (UNIV_LIKELY_NULL(block->page.zip.data)) @@ -1010,14 +1015,13 @@ static void btr_root_page_init(buf_block_t *block, index_id_t index_id, { static_assert(((FIL_PAGE_INDEX & 0xff00) | byte(FIL_PAGE_RTREE)) == FIL_PAGE_RTREE, "compatibility"); - mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->page.frame, - byte(FIL_PAGE_RTREE)); - if (mach_read_from_8(block->page.frame + FIL_RTREE_SPLIT_SEQ_NUM)) - mtr->memset(block, FIL_RTREE_SPLIT_SEQ_NUM, 8, 0); + mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + page, byte(FIL_PAGE_RTREE)); + if (mach_read_from_8(page + FIL_RTREE_SPLIT_SEQ_NUM)) + mtr->memset(block, page + FIL_RTREE_SPLIT_SEQ_NUM, 8, 0); } /* Set the level of the new index page */ - mtr->write<2,mtr_t::MAYBE_NOP>( - *block, PAGE_HEADER + PAGE_LEVEL + block->page.frame, 0U); + mtr->write<2,mtr_t::MAYBE_NOP> + (*block, PAGE_HEADER + PAGE_LEVEL + page, 0U); mtr->write<8,mtr_t::MAYBE_NOP>(*block, page_index_id, index_id); } } @@ -1041,6 +1045,7 @@ btr_create( dberr_t* err) { buf_block_t* block; + page_t* page; ut_ad(mtr->is_named_space(space)); ut_ad(index_id != BTR_FREED_INDEX_ID); @@ -1066,7 +1071,7 @@ btr_create( tree root page */ block = fseg_alloc_free_page_general( - buf_block_get_frame(ibuf_hdr_block) + ibuf_hdr_block->page.frame + IBUF_HEADER + IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO, FSP_UP, false, mtr, mtr, err); @@ -1077,7 +1082,10 @@ btr_create( ut_ad(block->page.id() == page_id_t(0,IBUF_TREE_ROOT_PAGE_NO)); - flst_init(block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr); + page = block->page.frame; + + flst_init(block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + page, + mtr); } else { block = fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr, err); @@ -1086,18 +1094,20 @@ btr_create( return(FIL_NULL); } + page = block->page.frame; + if (!fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr, err, false, block)) { /* Not enough space for new segment, free root segment before return. */ - btr_free_root(block, *space, mtr); + btr_free_root(block, page, *space, mtr); return(FIL_NULL); } } - ut_ad(!page_has_siblings(block->page.frame)); + ut_ad(!page_has_siblings(page)); - btr_root_page_init(block, index_id, index, mtr); + btr_root_page_init(block, page, index_id, index, mtr); /* We reset the free bits for the page in a separate mini-transaction to allow creation of several trees in the @@ -1115,8 +1125,7 @@ btr_create( allowed size fit on the root page: this fact is needed to ensure correctness of split algorithms */ - ut_ad(page_get_max_insert_size(block->page.frame, 2) - > 2 * BTR_PAGE_MAX_REC_SIZE); + ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE); return(block->page.id().page_no()); } @@ -1124,11 +1133,13 @@ btr_create( /** Free a B-tree except the root page. The root page MUST be freed after this by calling btr_free_root. @param[in,out] block root page +@param[in,out] page root page frame @param[in] log_mode mtr logging mode */ static void btr_free_but_not_root( buf_block_t* block, + page_t* page, mtr_log_t log_mode #ifdef BTR_CUR_HASH_ADAPT ,bool ahi=false @@ -1136,18 +1147,17 @@ btr_free_but_not_root( ) { mtr_t mtr; - - ut_ad(fil_page_index_page_check(block->page.frame)); - ut_ad(!page_has_siblings(block->page.frame)); + ut_ad(fil_page_index_page_check(page)); + ut_ad(!page_has_siblings(page)); leaf_loop: mtr_start(&mtr); ut_d(mtr.freeing_tree()); mtr_set_log_mode(&mtr, log_mode); fil_space_t *space = mtr.set_named_space_id(block->page.id().space()); - if (!btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF, + if (!btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + page, *block, *space) - || !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP, + || !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + page, *block, *space)) { mtr_commit(&mtr); return; @@ -1157,7 +1167,7 @@ btr_free_but_not_root( fsp0fsp. */ bool finished = fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_LEAF - + block->page.frame, &mtr + + page, &mtr #ifdef BTR_CUR_HASH_ADAPT , ahi #endif /* BTR_CUR_HASH_ADAPT */ @@ -1173,10 +1183,10 @@ btr_free_but_not_root( mtr_set_log_mode(&mtr, log_mode); space = mtr.set_named_space_id(block->page.id().space()); - finished = !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP, - *block, *space) + finished = !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + + page, *block, *space) || fseg_free_step_not_header(PAGE_HEADER + PAGE_BTR_SEG_TOP - + block->page.frame, &mtr + + page, &mtr #ifdef BTR_CUR_HASH_ADAPT ,ahi #endif /* BTR_CUR_HASH_ADAPT */ @@ -1209,7 +1219,8 @@ dberr_t dict_index_t::clear(que_thr_t *thr) table->space->zip_size(), RW_X_LATCH, nullptr, BUF_GET, &mtr, &err)) { - btr_free_but_not_root(root_block, mtr.get_log_mode() + page_t *root= root_block->page.frame; + btr_free_but_not_root(root_block, root, mtr.get_log_mode() #ifdef BTR_CUR_HASH_ADAPT ,n_ahi_pages() != 0 #endif @@ -1220,11 +1231,11 @@ dberr_t dict_index_t::clear(que_thr_t *thr) btr_search_drop_page_hash_index(root_block, false); ut_ad(n_ahi_pages() == 0); #endif - mtr.memset(root_block, PAGE_HEADER + PAGE_BTR_SEG_LEAF, + mtr.memset(root_block, PAGE_HEADER + PAGE_BTR_SEG_LEAF + root, FSEG_HEADER_SIZE, 0); if (fseg_create(table->space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, &mtr, &err, false, root_block)) - btr_root_page_init(root_block, id, this, &mtr); + btr_root_page_init(root_block, root, id, this, &mtr); } mtr.commit(); @@ -1243,9 +1254,10 @@ void btr_free_if_exists(fil_space_t *space, uint32_t page, space->zip_size(), index_id, mtr)) { - btr_free_but_not_root(root, mtr->get_log_mode()); + page_t *r= root->page.frame; + btr_free_but_not_root(root, r, mtr->get_log_mode()); mtr->set_named_space(space); - btr_free_root(root, *space, mtr); + btr_free_root(root, r, *space, mtr); } } @@ -1264,9 +1276,10 @@ void btr_drop_temporary_table(const dict_table_t &table) RW_X_LATCH, nullptr, BUF_GET, &mtr, nullptr, false)) { - btr_free_but_not_root(block, MTR_LOG_NO_REDO); + page_t *page= block->page.frame; + btr_free_but_not_root(block, page, MTR_LOG_NO_REDO); mtr.set_log_mode(MTR_LOG_NO_REDO); - btr_free_root(block, *fil_system.temp_space, &mtr); + btr_free_root(block, page, *fil_system.temp_space, &mtr); mtr.commit(); mtr.start(); } @@ -1399,34 +1412,36 @@ btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset) static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) { buf_block_t *const block= cursor->block; + page_t *const page= block->page.frame; ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); ut_ad(!is_buf_block_get_page_zip(block)); - ut_ad(fil_page_index_page_check(block->page.frame)); + ut_ad(fil_page_index_page_check(page)); ut_ad(cursor->index->is_dummy || block->page.id().space() == cursor->index->table->space->id); ut_ad(cursor->index->is_dummy || block->page.id().page_no() != cursor->index->page || - !page_has_siblings(block->page.frame)); + !page_has_siblings(page)); /* Save the cursor position. */ - const ulint pos= page_rec_get_n_recs_before(cursor->rec); + const ulint pos= page_rec_get_n_recs_before(page, cursor->rec); if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED)) return DB_CORRUPTION; btr_search_drop_page_hash_index(block, false); - buf_block_t *old= buf_block_alloc(); + buf_block_t *const old= buf_block_alloc(); + page_t *const opage= old->page.frame; + /* Copy the old page to temporary space */ - memcpy_aligned(old->page.frame, block->page.frame, - srv_page_size); + memcpy_aligned(opage, page, srv_page_size); const mtr_log_t log_mode= mtr->set_log_mode(MTR_LOG_NO_REDO); page_create(block, mtr, cursor->index->table->not_redundant()); if (cursor->index->is_spatial()) - block->page.frame[FIL_PAGE_TYPE + 1]= byte(FIL_PAGE_RTREE); + page[FIL_PAGE_TYPE + 1]= byte(FIL_PAGE_RTREE); static_assert(((FIL_PAGE_INDEX & 0xff00) | byte(FIL_PAGE_RTREE)) == FIL_PAGE_RTREE, "compatibility"); @@ -1435,8 +1450,7 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) do not copy the lock bits yet */ dberr_t err= - page_copy_rec_list_end_no_locks(block, old, - page_get_infimum_rec(old->page.frame), + page_copy_rec_list_end_no_locks(block, old, page_get_infimum_rec(opage), cursor->index, mtr); mtr->set_log_mode(log_mode); @@ -1444,15 +1458,15 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) return err; /* Copy the PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC. */ - ut_ad(!page_get_max_trx_id(block->page.frame)); - memcpy_aligned<8>(PAGE_MAX_TRX_ID + PAGE_HEADER + block->page.frame, - PAGE_MAX_TRX_ID + PAGE_HEADER + old->page.frame, 8); + ut_ad(!page_get_max_trx_id(page)); + memcpy_aligned<8>(PAGE_MAX_TRX_ID + PAGE_HEADER + page, + PAGE_MAX_TRX_ID + PAGE_HEADER + opage, 8); #ifdef UNIV_DEBUG - if (page_get_max_trx_id(block->page.frame)) + if (page_get_max_trx_id(page)) /* PAGE_MAX_TRX_ID must be zero on non-leaf pages other than clustered index root pages. */ ut_ad(dict_index_is_sec_or_ibuf(cursor->index) - ? page_is_leaf(block->page.frame) + ? page_is_leaf(page) : block->page.id().page_no() == cursor->index->page); else /* PAGE_MAX_TRX_ID is unused in clustered index pages (other than @@ -1461,16 +1475,14 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) page_create(). PAGE_MAX_TRX_ID must be nonzero on dict_index_is_sec_or_ibuf() leaf pages. */ ut_ad(cursor->index->table->is_temporary() || - !page_is_leaf(block->page.frame) || + !page_is_leaf(page) || !dict_index_is_sec_or_ibuf(cursor->index)); #endif - const uint16_t data_size1= page_get_data_size(old->page.frame); - const uint16_t data_size2= page_get_data_size(block->page.frame); - const ulint max1= - page_get_max_insert_size_after_reorganize(old->page.frame, 1); - const ulint max2= - page_get_max_insert_size_after_reorganize(block->page.frame, 1); + const uint16_t data_size1= page_get_data_size(opage); + const uint16_t data_size2= page_get_data_size(page); + const ulint max1= page_get_max_insert_size_after_reorganize(opage, 1); + const ulint max2= page_get_max_insert_size_after_reorganize(page, 1); if (UNIV_UNLIKELY(data_size1 != data_size2 || max1 != max2)) { @@ -1482,50 +1494,43 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) /* Restore the cursor position. */ if (!pos) - ut_ad(cursor->rec == page_get_infimum_rec(block->page.frame)); - else if (!(cursor->rec= page_rec_get_nth(block->page.frame, pos))) + ut_ad(cursor->rec == page_get_infimum_rec(page)); + else if (!(cursor->rec= page_rec_get_nth(page, pos))) return DB_CORRUPTION; if (block->page.id().page_no() != cursor->index->page || - fil_page_get_type(old->page.frame) != FIL_PAGE_TYPE_INSTANT) - ut_ad(!memcmp(old->page.frame, block->page.frame, PAGE_HEADER)); + fil_page_get_type(opage) != FIL_PAGE_TYPE_INSTANT) + ut_ad(!memcmp(opage, page, PAGE_HEADER)); else if (!cursor->index->is_instant()) { - ut_ad(!memcmp(old->page.frame, block->page.frame, FIL_PAGE_TYPE)); - ut_ad(!memcmp(old->page.frame + FIL_PAGE_TYPE + 2, - block->page.frame + FIL_PAGE_TYPE + 2, + ut_ad(!memcmp(opage, page, FIL_PAGE_TYPE)); + ut_ad(!memcmp(opage + FIL_PAGE_TYPE + 2, page + FIL_PAGE_TYPE + 2, PAGE_HEADER - FIL_PAGE_TYPE - 2)); - mtr->write<2,mtr_t::FORCED>(*block, FIL_PAGE_TYPE + block->page.frame, - FIL_PAGE_INDEX); + mtr->write<2,mtr_t::FORCED>(*block, FIL_PAGE_TYPE + page, FIL_PAGE_INDEX); } else { /* Preserve the PAGE_INSTANT information. */ - memcpy_aligned<2>(FIL_PAGE_TYPE + block->page.frame, - FIL_PAGE_TYPE + old->page.frame, 2); - memcpy_aligned<2>(PAGE_HEADER + PAGE_INSTANT + block->page.frame, - PAGE_HEADER + PAGE_INSTANT + old->page.frame, 2); + memcpy_aligned<2>(FIL_PAGE_TYPE + page, FIL_PAGE_TYPE + opage, 2); + memcpy_aligned<2>(PAGE_HEADER + PAGE_INSTANT + page, + PAGE_HEADER + PAGE_INSTANT + opage, 2); if (!cursor->index->table->instant); - else if (page_is_comp(block->page.frame)) + else if (page_is_comp(page)) { - memcpy(PAGE_NEW_INFIMUM + block->page.frame, - PAGE_NEW_INFIMUM + old->page.frame, 8); - memcpy(PAGE_NEW_SUPREMUM + block->page.frame, - PAGE_NEW_SUPREMUM + old->page.frame, 8); + memcpy(PAGE_NEW_INFIMUM + page, PAGE_NEW_INFIMUM + opage, 8); + memcpy(PAGE_NEW_SUPREMUM + page, PAGE_NEW_SUPREMUM + opage, 8); } else { - memcpy(PAGE_OLD_INFIMUM + block->page.frame, - PAGE_OLD_INFIMUM + old->page.frame, 8); - memcpy(PAGE_OLD_SUPREMUM + block->page.frame, - PAGE_OLD_SUPREMUM + old->page.frame, 8); + memcpy(PAGE_OLD_INFIMUM + page, PAGE_OLD_INFIMUM + opage, 8); + memcpy(PAGE_OLD_SUPREMUM + page, PAGE_OLD_SUPREMUM + opage, 8); } - ut_ad(!memcmp(old->page.frame, block->page.frame, PAGE_HEADER)); + ut_ad(!memcmp(opage, page, PAGE_HEADER)); } - ut_ad(!memcmp(old->page.frame + PAGE_MAX_TRX_ID + PAGE_HEADER, - block->page.frame + PAGE_MAX_TRX_ID + PAGE_HEADER, + ut_ad(!memcmp(opage + PAGE_MAX_TRX_ID + PAGE_HEADER, + page + PAGE_MAX_TRX_ID + PAGE_HEADER, PAGE_DATA - (PAGE_MAX_TRX_ID + PAGE_HEADER))); if (!cursor->index->has_locking()); @@ -1541,102 +1546,96 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) ulint a, e; for (a= PAGE_HEADER, e= PAGE_MAX_TRX_ID + PAGE_HEADER; a < e; a++) { - if (old->page.frame[a] == block->page.frame[a]) + if (opage[a] == page[a]) continue; - while (--e, old->page.frame[e] == block->page.frame[e]); + while (--e, opage[e] == page[e]); e++; ut_ad(a < e); /* Write log for the changed page header fields. */ - mtr->memcpy(*block, a, e - a); + mtr->memcpy(*block, page + a, e - a); break; } - const uint16_t top= page_header_get_offs(block->page.frame, PAGE_HEAP_TOP); + const uint16_t top= page_header_get_offs(page, PAGE_HEAP_TOP); - if (page_is_comp(block->page.frame)) + if (page_is_comp(page)) { /* info_bits=0, n_owned=1, heap_no=0, status */ - ut_ad(!memcmp(PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES + - block->page.frame, - PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES + - old->page.frame, 3)); + ut_ad(!memcmp(PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES + page, + PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES + opage, 3)); /* If the 'next' pointer of the infimum record has changed, log it. */ a= PAGE_NEW_INFIMUM - 2; e= a + 2; - if (block->page.frame[a] == old->page.frame[a]) + if (page[a] == opage[a]) a++; - if (--e, block->page.frame[e] != old->page.frame[e]) + if (--e, page[e] != opage[e]) e++; if (ulint len= e - a) - mtr->memcpy(*block, a, len); + mtr->memcpy(*block, page + a, len); /* The infimum record itself must not change. */ - ut_ad(!memcmp(PAGE_NEW_INFIMUM + block->page.frame, - PAGE_NEW_INFIMUM + old->page.frame, 8)); + ut_ad(!memcmp(PAGE_NEW_INFIMUM + page, PAGE_NEW_INFIMUM + opage, 8)); /* Log any change of the n_owned of the supremum record. */ a= PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES; - if (block->page.frame[a] != old->page.frame[a]) - mtr->memcpy(*block, a, 1); + if (page[a] != opage[a]) + mtr->memcpy(*block, page + a, 1); /* The rest of the supremum record must not change. */ - ut_ad(!memcmp(&block->page.frame[a + 1], &old->page.frame[a + 1], + ut_ad(!memcmp(&page[a + 1], &opage[a + 1], PAGE_NEW_SUPREMUM_END - PAGE_NEW_SUPREMUM + REC_N_NEW_EXTRA_BYTES - 1)); /* Log the differences in the payload. */ for (a= PAGE_NEW_SUPREMUM_END, e= top; a < e; a++) { - if (old->page.frame[a] == block->page.frame[a]) + if (opage[a] == page[a]) continue; - while (--e, old->page.frame[e] == block->page.frame[e]); + while (--e, opage[e] == page[e]); e++; ut_ad(a < e); /* TODO: write MEMMOVE records to minimize this further! */ - mtr->memcpy(*block, a, e - a); + mtr->memcpy(*block, page + a, e - a); break; } } else { /* info_bits=0, n_owned=1, heap_no=0, number of fields, 1-byte format */ - ut_ad(!memcmp(PAGE_OLD_INFIMUM - REC_N_OLD_EXTRA_BYTES + - block->page.frame, - PAGE_OLD_INFIMUM - REC_N_OLD_EXTRA_BYTES + - old->page.frame, 4)); + ut_ad(!memcmp(PAGE_OLD_INFIMUM - REC_N_OLD_EXTRA_BYTES + page, + PAGE_OLD_INFIMUM - REC_N_OLD_EXTRA_BYTES + opage, 4)); /* If the 'next' pointer of the infimum record has changed, log it. */ a= PAGE_OLD_INFIMUM - 2; e= a + 2; - if (block->page.frame[a] == old->page.frame[a]) + if (page[a] == opage[a]) a++; - if (--e, block->page.frame[e] != old->page.frame[e]) + if (--e, page[e] != opage[e]) e++; if (ulint len= e - a) - mtr->memcpy(*block, a, len); + mtr->memcpy(*block, page + a, len); /* The infimum record itself must not change. */ - ut_ad(!memcmp(PAGE_OLD_INFIMUM + block->page.frame, - PAGE_OLD_INFIMUM + old->page.frame, 8)); + ut_ad(!memcmp(PAGE_OLD_INFIMUM + page, PAGE_OLD_INFIMUM + opage, 8)); /* Log any change of the n_owned of the supremum record. */ a= PAGE_OLD_SUPREMUM - REC_N_OLD_EXTRA_BYTES; - if (block->page.frame[a] != old->page.frame[a]) - mtr->memcpy(*block, a, 1); - ut_ad(!memcmp(&block->page.frame[a + 1], &old->page.frame[a + 1], + if (page[a] != opage[a]) + mtr->memcpy(*block, page + a, 1); + ut_ad(!memcmp(&page[a + 1], &opage[a + 1], PAGE_OLD_SUPREMUM_END - PAGE_OLD_SUPREMUM + REC_N_OLD_EXTRA_BYTES - 1)); /* Log the differences in the payload. */ for (a= PAGE_OLD_SUPREMUM_END, e= top; a < e; a++) { - if (old->page.frame[a] == block->page.frame[a]) + if (opage[a] == page[a]) continue; - while (--e, old->page.frame[e] == block->page.frame[e]); + while (--e, opage[e] == page[e]); e++; ut_ad(a < e); /* TODO: write MEMMOVE records to minimize this further! */ - mtr->memcpy(*block, a, e - a); + mtr->memcpy(*block, page + a, e - a); break; } } e= srv_page_size - PAGE_DIR; - a= e - PAGE_DIR_SLOT_SIZE * page_dir_get_n_slots(block->page.frame); + a= e - PAGE_DIR_SLOT_SIZE * page_dir_get_n_slots(page); /* Zero out the payload area. */ mtr->memset(*block, top, a - top, 0); @@ -1644,13 +1643,13 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr) /* Log changes to the page directory. */ for (; a < e; a++) { - if (old->page.frame[a] == block->page.frame[a]) + if (opage[a] == page[a]) continue; - while (--e, old->page.frame[e] == block->page.frame[e]); + while (--e, opage[e] == page[e]); e++; ut_ad(a < e); /* Write log for the changed page directory slots. */ - mtr->memcpy(*block, a, e - a); + mtr->memcpy(*block, page + a, e - a); break; } } @@ -1707,7 +1706,8 @@ dberr_t btr_page_reorganize(page_cur_t *cursor, mtr_t *mtr) if (!buf_block_get_page_zip(cursor->block)) return btr_page_reorganize_low(cursor, mtr); - ulint pos= page_rec_get_n_recs_before(cursor->rec); + page_t *page= page_cur_get_page(cursor); + ulint pos= page_rec_get_n_recs_before(page, cursor->rec); if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED)) return DB_CORRUPTION; @@ -1715,8 +1715,8 @@ dberr_t btr_page_reorganize(page_cur_t *cursor, mtr_t *mtr) page_zip_level, mtr, true); if (err == DB_FAIL); else if (!pos) - ut_ad(cursor->rec == page_get_infimum_rec(cursor->block->page.frame)); - else if (!(cursor->rec= page_rec_get_nth(cursor->block->page.frame, pos))) + ut_ad(cursor->rec == page_get_infimum_rec(page)); + else if (!(cursor->rec= page_rec_get_nth(page, pos))) err= DB_CORRUPTION; return err; @@ -1746,6 +1746,7 @@ btr_page_empty( #endif /* UNIV_ZIP_DEBUG */ btr_search_drop_page_hash_index(block, false); + page_t* const page = block->page.frame; /* Recreate the page: note that global data on page (possible segment headers, next page-field, etc.) is preserved intact */ @@ -1755,7 +1756,7 @@ btr_page_empty( const ib_uint64_t autoinc = dict_index_is_clust(index) && index->page == block->page.id().page_no() - ? page_get_autoinc(block->page.frame) + ? page_get_autoinc(page) : 0; if (page_zip) { @@ -1766,20 +1767,19 @@ btr_page_empty( static_assert(((FIL_PAGE_INDEX & 0xff00) | byte(FIL_PAGE_RTREE)) == FIL_PAGE_RTREE, "compatibility"); - mtr->write<1>(*block, FIL_PAGE_TYPE + 1 - + block->page.frame, + mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + page, byte(FIL_PAGE_RTREE)); - if (mach_read_from_8(block->page.frame - + FIL_RTREE_SPLIT_SEQ_NUM)) { - mtr->memset(block, FIL_RTREE_SPLIT_SEQ_NUM, + if (mach_read_from_8(page + FIL_RTREE_SPLIT_SEQ_NUM)) { + mtr->memset(block, + page + FIL_RTREE_SPLIT_SEQ_NUM, 8, 0); } } mtr->write<2,mtr_t::MAYBE_NOP>(*block, PAGE_HEADER + PAGE_LEVEL - + block->page.frame, level); + + page, level); if (autoinc) { mtr->write<8>(*block, PAGE_HEADER + PAGE_MAX_TRX_ID - + block->page.frame, autoinc); + + page, autoinc); } } } @@ -1793,20 +1793,22 @@ void btr_set_instant(buf_block_t* root, const dict_index_t& index, mtr_t* mtr) ut_ad(index.n_core_fields > 0); ut_ad(index.n_core_fields < REC_MAX_N_FIELDS); ut_ad(index.is_instant()); - ut_ad(fil_page_get_type(root->page.frame) == FIL_PAGE_TYPE_INSTANT - || fil_page_get_type(root->page.frame) == FIL_PAGE_INDEX); - ut_ad(!page_has_siblings(root->page.frame)); + + page_t* const r = root->page.frame; + + ut_ad(fil_page_get_type(r) == FIL_PAGE_TYPE_INSTANT + || fil_page_get_type(r) == FIL_PAGE_INDEX); + ut_ad(!page_has_siblings(r)); ut_ad(root->page.id().page_no() == index.page); - rec_t* infimum = page_get_infimum_rec(root->page.frame); - rec_t* supremum = page_get_supremum_rec(root->page.frame); - byte* page_type = root->page.frame + FIL_PAGE_TYPE; - uint16_t i = page_header_get_field(root->page.frame, PAGE_INSTANT); + rec_t* infimum = page_get_infimum_rec(r); + rec_t* supremum = page_get_supremum_rec(r); + byte* page_type = r + FIL_PAGE_TYPE; + uint16_t i = page_header_get_field(r, PAGE_INSTANT); switch (mach_read_from_2(page_type)) { case FIL_PAGE_TYPE_INSTANT: - ut_ad(page_get_instant(root->page.frame) - == index.n_core_fields); + ut_ad(page_get_instant(r) == index.n_core_fields); if (memcmp(infimum, "infimum", 8) || memcmp(supremum, "supremum", 8)) { ut_ad(index.table->instant); @@ -1823,21 +1825,19 @@ void btr_set_instant(buf_block_t* root, const dict_index_t& index, mtr_t* mtr) ut_ad("wrong page type" == 0); /* fall through */ case FIL_PAGE_INDEX: - ut_ad(!page_is_comp(root->page.frame) - || !page_get_instant(root->page.frame)); + ut_ad(!page_is_comp(r) || !page_get_instant(r)); ut_ad(!memcmp(infimum, "infimum", 8)); ut_ad(!memcmp(supremum, "supremum", 8)); mtr->write<2>(*root, page_type, FIL_PAGE_TYPE_INSTANT); ut_ad(i <= PAGE_NO_DIRECTION); i |= static_cast(index.n_core_fields << 3); - mtr->write<2>(*root, PAGE_HEADER + PAGE_INSTANT - + root->page.frame, i); + mtr->write<2>(*root, PAGE_HEADER + PAGE_INSTANT + r, i); break; } if (index.table->instant) { - mtr->memset(root, infimum - root->page.frame, 8, 0); - mtr->memset(root, supremum - root->page.frame, 7, 0); + mtr->memset(root, infimum, 8, 0); + mtr->memset(root, supremum, 7, 0); mtr->write<1,mtr_t::MAYBE_NOP>(*root, &supremum[7], index.n_core_null_bytes); } @@ -1852,14 +1852,15 @@ void btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr) { ut_ad(!index.table->is_temporary()); ut_ad(index.is_primary()); - buf_block_t *root= btr_get_latched_root(index, mtr); - byte *page_type= root->page.frame + FIL_PAGE_TYPE; + buf_block_t *const root= btr_get_latched_root(index, mtr); + page_t *const r= root->page.frame; + byte *page_type= r + FIL_PAGE_TYPE; if (all) { ut_ad(mach_read_from_2(page_type) == FIL_PAGE_TYPE_INSTANT || mach_read_from_2(page_type) == FIL_PAGE_INDEX); mtr->write<2,mtr_t::MAYBE_NOP>(*root, page_type, FIL_PAGE_INDEX); - byte *instant= PAGE_INSTANT + PAGE_HEADER + root->page.frame; + byte *instant= PAGE_INSTANT + PAGE_HEADER + r; mtr->write<2,mtr_t::MAYBE_NOP>(*root, instant, page_ptr_get_direction(instant + 1)); } @@ -1867,7 +1868,7 @@ void btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr) ut_ad(mach_read_from_2(page_type) == FIL_PAGE_TYPE_INSTANT); static const byte supremuminfimum[8 + 8] = "supremuminfimum"; uint16_t infimum, supremum; - if (page_is_comp(root->page.frame)) + if (page_is_comp(r)) { infimum= PAGE_NEW_INFIMUM; supremum= PAGE_NEW_SUPREMUM; @@ -1877,12 +1878,10 @@ void btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr) infimum= PAGE_OLD_INFIMUM; supremum= PAGE_OLD_SUPREMUM; } - ut_ad(!memcmp(&root->page.frame[infimum], supremuminfimum + 8, 8) == - !memcmp(&root->page.frame[supremum], supremuminfimum, 8)); - mtr->memcpy(*root, &root->page.frame[infimum], - supremuminfimum + 8, 8); - mtr->memcpy(*root, &root->page.frame[supremum], - supremuminfimum, 8); + ut_ad(!memcmp(&r[infimum], supremuminfimum + 8, 8) == + !memcmp(&r[supremum], supremuminfimum, 8)); + mtr->memcpy(*root, &r[infimum], supremuminfimum + 8, 8); + mtr->memcpy(*root, &r[supremum], supremuminfimum, 8); } /*************************************************************//** @@ -1913,19 +1912,17 @@ btr_root_raise_and_insert( ulint level; rec_t* node_ptr_rec; page_cur_t* page_cursor; - page_zip_des_t* root_page_zip; - page_zip_des_t* new_page_zip; - buf_block_t* root; - buf_block_t* new_block; - root = btr_cur_get_block(cursor); - root_page_zip = buf_block_get_page_zip(root); - ut_ad(!page_is_empty(root->page.frame)); + buf_block_t* root = btr_cur_get_block(cursor); + page_zip_des_t* root_page_zip = buf_block_get_page_zip(root); + page_t* const r = root->page.frame; + + ut_ad(!page_is_empty(r)); index = btr_cur_get_index(cursor); ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable)); #ifdef UNIV_ZIP_DEBUG ut_a(!root_page_zip - || page_zip_validate(root_page_zip, root->page.frame, index)); + || page_zip_validate(root_page_zip, r, index)); #endif /* UNIV_ZIP_DEBUG */ const page_id_t root_id{root->page.id()}; @@ -1939,10 +1936,12 @@ btr_root_raise_and_insert( } if (index->is_ibuf()) { - } else if (!btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF, - *root, *index->table->space) - || !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP, - *root, *index->table->space)) { + } else if (!btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + + r, + *root, *index->table->space) + || !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + + r, + *root, *index->table->space)) { return nullptr; } @@ -1950,28 +1949,30 @@ btr_root_raise_and_insert( moving the root records to the new page, emptying the root, putting a node pointer to the new page, and then splitting the new page. */ - level = btr_page_get_level(root->page.frame); + level = btr_page_get_level(r); - new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr, err); + buf_block_t* new_block = btr_page_alloc( + index, 0, FSP_NO_DIR, level, mtr, mtr, err); if (!new_block) { return nullptr; } - new_page_zip = buf_block_get_page_zip(new_block); - ut_a(!new_page_zip == !root_page_zip); - ut_a(!new_page_zip - || page_zip_get_size(new_page_zip) - == page_zip_get_size(root_page_zip)); + page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block); + ut_ad(!new_page_zip == !root_page_zip); + ut_ad(!new_page_zip + || page_zip_get_size(new_page_zip) + == page_zip_get_size(root_page_zip)); + + page_t* const n = new_block->page.frame; btr_page_create(new_block, new_page_zip, index, level, mtr); - if (page_has_siblings(new_block->page.frame)) { + if (page_has_siblings(n)) { compile_time_assert(FIL_PAGE_NEXT == FIL_PAGE_PREV + 4); compile_time_assert(FIL_NULL == 0xffffffff); static_assert(FIL_PAGE_PREV % 8 == 0, "alignment"); - memset_aligned<8>(new_block->page.frame + FIL_PAGE_PREV, - 0xff, 8); - mtr->memset(new_block, FIL_PAGE_PREV, 8, 0xff); + memset_aligned<8>(n + FIL_PAGE_PREV, 0xff, 8); + mtr->memset(new_block, n + FIL_PAGE_PREV, 8, 0xff); if (UNIV_LIKELY_NULL(new_page_zip)) { memset_aligned<8>(new_page_zip->data + FIL_PAGE_PREV, 0xff, 8); @@ -1984,7 +1985,7 @@ btr_root_raise_and_insert( || new_page_zip #endif /* UNIV_ZIP_COPY */ || !page_copy_rec_list_end(new_block, root, - page_get_infimum_rec(root->page.frame), + page_get_infimum_rec(r), index, mtr, err)) { switch (*err) { case DB_SUCCESS: @@ -1999,14 +2000,12 @@ btr_root_raise_and_insert( ut_a(new_page_zip); /* Copy the page byte for byte. */ - page_zip_copy_recs(new_block, root_page_zip, - root->page.frame, index, mtr); + page_zip_copy_recs(new_block, root_page_zip, r, index, mtr); /* Update the lock table and possible hash index. */ if (index->has_locking()) { - lock_move_rec_list_end( - new_block, root, - page_get_infimum_rec(root->page.frame)); + lock_move_rec_list_end(new_block, root, + page_get_infimum_rec(r)); } /* Move any existing predicate locks */ @@ -2026,9 +2025,9 @@ btr_root_raise_and_insert( longer is a leaf page. (Older versions of InnoDB did set PAGE_MAX_TRX_ID on all secondary index pages.) */ byte* p = my_assume_aligned<8>( - PAGE_HEADER + PAGE_MAX_TRX_ID + root->page.frame); + PAGE_HEADER + PAGE_MAX_TRX_ID + r); if (mach_read_from_8(p)) { - mtr->memset(root, max_trx_id, 8, 0); + mtr->memset(root, p, 8, 0); if (UNIV_LIKELY_NULL(root->page.zip.data)) { memset_aligned<8>(max_trx_id + root->page.zip.data, 0, 8); @@ -2039,9 +2038,9 @@ btr_root_raise_and_insert( root page; on other clustered index pages, we want to reserve the field PAGE_MAX_TRX_ID for future use. */ byte* p = my_assume_aligned<8>( - PAGE_HEADER + PAGE_MAX_TRX_ID + new_block->page.frame); + PAGE_HEADER + PAGE_MAX_TRX_ID + n); if (mach_read_from_8(p)) { - mtr->memset(new_block, max_trx_id, 8, 0); + mtr->memset(new_block, p, 8, 0); if (UNIV_LIKELY_NULL(new_block->page.zip.data)) { memset_aligned<8>(max_trx_id + new_block->page.zip.data, @@ -2065,7 +2064,7 @@ btr_root_raise_and_insert( } const uint32_t new_page_no = new_block->page.id().page_no(); - rec = page_rec_get_next(page_get_infimum_rec(new_block->page.frame)); + rec = page_rec_get_first(n); ut_ad(rec); /* We just created the page. */ /* Build the node pointer (= node key and page address) for the @@ -2090,14 +2089,14 @@ btr_root_raise_and_insert( /* Rebuild the root page to get free space */ btr_page_empty(root, root_page_zip, index, level + 1, mtr); /* btr_page_empty() is supposed to zero-initialize the field. */ - ut_ad(!page_get_instant(root->page.frame)); + ut_ad(!page_get_instant(r)); if (index->is_instant()) { ut_ad(!root_page_zip); btr_set_instant(root, *index, mtr); } - ut_ad(!page_has_siblings(root->page.frame)); + ut_ad(!page_has_siblings(r)); page_cursor = btr_cur_get_page_cur(cursor); @@ -2146,13 +2145,14 @@ converging to the left. rec_t* btr_page_get_split_rec_to_left(const btr_cur_t* cursor) { rec_t* split_rec = btr_cur_get_rec(cursor); - const page_t* page = page_align(split_rec); + page_t* page = btr_cur_get_page(cursor); if (page_header_get_ptr(page, PAGE_LAST_INSERT) - != page_rec_get_next(split_rec)) { + != page_rec_get_next(page, split_rec)) { return NULL; } + const rec_t* infimum = page_get_infimum_rec(page); /* The metadata record must be present in the leftmost leaf page of the clustered index, if and only if index->is_instant(). However, during innobase_instant_try(), index->is_instant() @@ -2162,21 +2162,18 @@ rec_t* btr_page_get_split_rec_to_left(const btr_cur_t* cursor) index->is_instant() must hold. */ ut_ad(!page_is_leaf(page) || page_has_prev(page) || cursor->index()->is_instant() - || !(rec_get_info_bits(page_rec_get_next_const( - page_get_infimum_rec(page)), + || !(rec_get_info_bits(page_rec_get_next(page, infimum), cursor->index()->table->not_redundant()) & REC_INFO_MIN_REC_FLAG)); - const rec_t* infimum = page_get_infimum_rec(page); - /* If the convergence is in the middle of a page, include also the record immediately before the new insert to the upper page. Otherwise, we could repeatedly move from page to page lots of records smaller than the convergence point. */ if (split_rec == infimum - || split_rec == page_rec_get_next_const(infimum)) { - split_rec = page_rec_get_next(split_rec); + || split_rec == page_rec_get_next(page, infimum)) { + split_rec = page_rec_get_next(page, split_rec); } return split_rec; @@ -2194,7 +2191,7 @@ bool btr_page_get_split_rec_to_right(const btr_cur_t* cursor, rec_t** split_rec) { rec_t* insert_point = btr_cur_get_rec(cursor); - const page_t* page = page_align(insert_point); + page_t* page = btr_cur_get_page(cursor); /* We use eager heuristics: if the new insert would be right after the previous insert on the same page, we assume that there is a @@ -2204,13 +2201,13 @@ btr_page_get_split_rec_to_right(const btr_cur_t* cursor, rec_t** split_rec) return false; } - insert_point = page_rec_get_next(insert_point); + insert_point = page_rec_get_next(page, insert_point); - if (!insert_point || page_rec_is_supremum(insert_point)) { + if (!insert_point || page_rec_is_supremum(page, insert_point)) { insert_point = NULL; } else { - insert_point = page_rec_get_next(insert_point); - if (page_rec_is_supremum(insert_point)) { + insert_point = page_rec_get_next(page, insert_point); + if (page_rec_is_supremum(page, insert_point)) { insert_point = NULL; } @@ -2300,9 +2297,9 @@ btr_page_get_split_rec( rec = NULL; /* NULL denotes that tuple is now included */ } else if (rec == NULL) { - rec = page_rec_get_next(ins_rec); + rec = page_rec_get_next(page, ins_rec); } else { - rec = page_rec_get_next(rec); + rec = page_rec_get_next(page, rec); } if (rec == NULL) { @@ -2332,12 +2329,12 @@ btr_page_get_split_rec( goto func_exit; } else if (rec == NULL) { - next_rec = page_rec_get_next(ins_rec); + next_rec = page_rec_get_next(page, ins_rec); } else { - next_rec = page_rec_get_next(rec); + next_rec = page_rec_get_next(page, rec); } ut_ad(next_rec); - if (!page_rec_is_supremum(next_rec)) { + if (!page_rec_is_supremum(page, next_rec)) { rec = next_rec; } } @@ -2397,14 +2394,14 @@ btr_page_insert_fits( inserted. */ if (!(end_rec = split_rec)) { - end_rec = page_rec_get_next(btr_cur_get_rec(cursor)); + end_rec = page_rec_get_next(page, btr_cur_get_rec(cursor)); } else if (cmp_dtuple_rec(tuple, split_rec, *offsets) < 0) { rec = split_rec; end_rec = page_get_supremum_rec(page); goto got_rec; } - if (!(rec = page_rec_get_next(page_get_infimum_rec(page)))) { + if (!(rec = page_rec_get_first(page))) { return false; } @@ -2440,7 +2437,7 @@ btr_page_insert_fits( return(true); } - if (!(rec = page_rec_get_next_const(rec))) { + if (!(rec = page_rec_get_next(page, rec))) { break; } } @@ -2595,13 +2592,14 @@ btr_attach_half_pages( } /* Get the level of the split pages */ - const ulint level = btr_page_get_level(block->page.frame); + page_t* const page = block->page.frame; + const ulint level = btr_page_get_level(page); ut_ad(level == btr_page_get_level(new_block->page.frame)); page_id_t id{block->page.id()}; /* Get the previous and next pages of page */ - const uint32_t prev_page_no = btr_page_get_prev(block->page.frame); - const uint32_t next_page_no = btr_page_get_next(block->page.frame); + const uint32_t prev_page_no = btr_page_get_prev(page); + const uint32_t next_page_no = btr_page_get_next(page); /* for consistency, both blocks should be locked, before change */ if (prev_page_no != FIL_NULL && direction == FSP_DOWN) { @@ -2652,43 +2650,46 @@ btr_attach_half_pages( /* Update page links of the level */ if (prev_block) { - if (UNIV_UNLIKELY(memcmp_aligned<4>(prev_block->page.frame - + FIL_PAGE_NEXT, - block->page.frame - + FIL_PAGE_OFFSET, - 4))) { + page_t* prev_page = prev_block->page.frame; + + if (UNIV_UNLIKELY(memcmp_aligned<4>(prev_page + FIL_PAGE_NEXT, + page + FIL_PAGE_OFFSET, + 4))) { return DB_CORRUPTION; } - btr_page_set_next(prev_block, lower_block->page.id().page_no(), - mtr); + btr_page_set_next(prev_block, prev_page, + lower_block->page.id().page_no(), mtr); } if (next_block) { - if (UNIV_UNLIKELY(memcmp_aligned<4>(next_block->page.frame - + FIL_PAGE_PREV, - block->page.frame - + FIL_PAGE_OFFSET, - 4))) { + page_t* next_page = next_block->page.frame; + + if (UNIV_UNLIKELY(memcmp_aligned<4>(next_page + FIL_PAGE_PREV, + page + FIL_PAGE_OFFSET, + 4))) { return DB_CORRUPTION; } - btr_page_set_prev(next_block, upper_block->page.id().page_no(), - mtr); + btr_page_set_prev(next_block, next_page, + upper_block->page.id().page_no(), mtr); } + page_t* lower_page = lower_block->page.frame; + page_t* upper_page = upper_block->page.frame; + if (direction == FSP_DOWN) { ut_ad(lower_block == new_block); - ut_ad(btr_page_get_next(upper_block->page.frame) - == next_page_no); - btr_page_set_prev(lower_block, prev_page_no, mtr); + ut_ad(btr_page_get_next(upper_page) == next_page_no); + btr_page_set_prev(lower_block, lower_page, prev_page_no, mtr); } else { ut_ad(upper_block == new_block); - ut_ad(btr_page_get_prev(lower_block->page.frame) - == prev_page_no); - btr_page_set_next(upper_block, next_page_no, mtr); + ut_ad(btr_page_get_prev(lower_page) == prev_page_no); + btr_page_set_next(upper_block, upper_page, next_page_no, mtr); } - btr_page_set_prev(upper_block, lower_block->page.id().page_no(), mtr); - btr_page_set_next(lower_block, upper_block->page.id().page_no(), mtr); + btr_page_set_prev(upper_block, upper_page, + lower_block->page.id().page_no(), mtr); + btr_page_set_next(lower_block, lower_page, + upper_block->page.id().page_no(), mtr); return DB_SUCCESS; } @@ -2752,7 +2753,7 @@ btr_insert_into_right_sibling( mtr_t* mtr) { buf_block_t* block = btr_cur_get_block(cursor); - page_t* page = buf_block_get_frame(block); + page_t* page = btr_cur_get_page(cursor); const uint32_t next_page_no = btr_page_get_next(page); ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock, @@ -2761,15 +2762,14 @@ btr_insert_into_right_sibling( ut_ad(heap); ut_ad(dtuple_check_typed(tuple)); - if (next_page_no == FIL_NULL || !page_rec_is_supremum( - page_rec_get_next(btr_cur_get_rec(cursor)))) { - + if (next_page_no == FIL_NULL + || !page_rec_is_last(btr_cur_get_page(cursor), + btr_cur_get_rec(cursor))) { return nullptr; } page_cur_t next_page_cursor; buf_block_t* next_block; - page_t* next_page; btr_cur_t next_father_cursor; rec_t* rec = nullptr; ulint max_size; @@ -2779,7 +2779,7 @@ btr_insert_into_right_sibling( if (UNIV_UNLIKELY(!next_block)) { return nullptr; } - next_page = buf_block_get_frame(next_block); + page_t* next_page = next_block->page.frame; const bool is_leaf = page_is_leaf(next_page); next_page_cursor.index = cursor->index(); @@ -2829,7 +2829,7 @@ btr_insert_into_right_sibling( *btr_cur_get_page_cur(cursor) = next_page_cursor; ut_ad(btr_cur_get_rec(cursor) == page_get_infimum_rec(next_page)); - ut_ad(page_rec_get_next(page_get_infimum_rec(next_page)) == rec); + ut_ad(page_rec_get_first(next_page) == rec); /* We have to change the parent node pointer */ @@ -2894,7 +2894,7 @@ page_move_rec_list_end( dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr) /*!< in: mtr */ { - page_t* new_page = buf_block_get_frame(new_block); + page_t* new_page = new_block->page.frame; ulint old_data_size; ulint new_data_size; ulint old_n_recs; @@ -2984,10 +2984,8 @@ btr_page_split_and_insert( dberr_t* err) /*!< out: error code */ { buf_block_t* block; - page_t* page; page_zip_des_t* page_zip; buf_block_t* new_block; - page_t* new_page; page_zip_des_t* new_page_zip; rec_t* split_rec; buf_block_t* left_block; @@ -3027,7 +3025,7 @@ btr_page_split_and_insert( ut_ad(cursor->index()->lock.have_u_or_x()); block = btr_cur_get_block(cursor); - page = buf_block_get_frame(block); + page_t* page = btr_cur_get_page(cursor); page_zip = buf_block_get_page_zip(block); ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); @@ -3067,8 +3065,7 @@ btr_page_split_and_insert( split_rec = page_get_middle_rec(page); } else if (btr_page_tuple_smaller(cursor, tuple, offsets, n_uniq, heap)) { - split_rec = page_rec_get_next( - page_get_infimum_rec(page)); + split_rec = page_rec_get_first(page); } else { split_rec = NULL; goto got_split_rec; @@ -3090,7 +3087,7 @@ btr_page_split_and_insert( return nullptr; } - new_page = buf_block_get_frame(new_block); + page_t* new_page = new_block->page.frame; new_page_zip = buf_block_get_page_zip(new_block); if (page_level && UNIV_LIKELY_NULL(new_page_zip)) { @@ -3135,9 +3132,9 @@ btr_page_split_and_insert( *err = DB_CORRUPTION; return nullptr; } - first_rec = page_rec_get_next(page_get_infimum_rec(page)); + first_rec = page_rec_get_first(page); insert_move_limit: - move_limit = page_rec_get_next(btr_cur_get_rec(cursor)); + move_limit = page_rec_get_next(page, btr_cur_get_rec(cursor)); if (UNIV_UNLIKELY(!first_rec || !move_limit)) { goto corrupted; } @@ -3335,9 +3332,7 @@ btr_page_split_and_insert( #ifdef UNIV_ZIP_DEBUG { - page_t* insert_page - = buf_block_get_frame(insert_block); - + page_t* insert_page = insert_block->page.frame; page_zip_des_t* insert_page_zip = buf_block_get_page_zip(insert_block); @@ -3400,10 +3395,8 @@ btr_page_split_and_insert( left_block, right_block, mtr); } - ut_ad(page_validate(buf_block_get_frame(left_block), - page_cursor->index)); - ut_ad(page_validate(buf_block_get_frame(right_block), - page_cursor->index)); + ut_ad(page_validate(left_block->page.frame, page_cursor->index)); + ut_ad(page_validate(right_block->page.frame, page_cursor->index)); ut_ad(!rec || rec_offs_validate(rec, page_cursor->index, *offsets)); return(rec); @@ -3419,9 +3412,10 @@ dberr_t btr_level_list_remove(const buf_block_t& block, ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_X_FIX)); ut_ad(block.zip_size() == index.table->space->zip_size()); ut_ad(index.table->space->id == block.page.id().space()); + const page_t *const page= block.page.frame; /* Get the previous and next page numbers of page */ - const uint32_t prev_page_no= btr_page_get_prev(block.page.frame); - const uint32_t next_page_no= btr_page_get_next(block.page.frame); + const uint32_t prev_page_no= btr_page_get_prev(page); + const uint32_t next_page_no= btr_page_get_next(page); page_id_t id{block.page.id()}; buf_block_t *prev= nullptr, *next; dberr_t err; @@ -3436,7 +3430,7 @@ dberr_t btr_level_list_remove(const buf_block_t& block, { ut_ad(mtr->memo_contains(index.lock, MTR_MEMO_X_LOCK)); prev= btr_block_get(index, id.page_no(), RW_X_LATCH, - page_is_leaf(block.page.frame), mtr, &err); + page_is_leaf(page), mtr, &err); if (UNIV_UNLIKELY(!prev)) return err; } @@ -3452,16 +3446,16 @@ dberr_t btr_level_list_remove(const buf_block_t& block, { ut_ad(mtr->memo_contains(index.lock, MTR_MEMO_X_LOCK)); next= btr_block_get(index, id.page_no(), RW_X_LATCH, - page_is_leaf(block.page.frame), mtr, &err); + page_is_leaf(page), mtr, &err); if (UNIV_UNLIKELY(!next)) return err; } #endif - btr_page_set_prev(next, prev_page_no, mtr); + btr_page_set_prev(next, next->page.frame, prev_page_no, mtr); } if (prev) - btr_page_set_next(prev, next_page_no, mtr); + btr_page_set_next(prev, prev->page.frame, next_page_no, mtr); return DB_SUCCESS; } @@ -3483,7 +3477,7 @@ btr_lift_page_up( buf_block_t* father_block; ulint page_level; page_zip_des_t* father_page_zip; - page_t* page = buf_block_get_frame(block); + page_t* page = block->page.frame; ulint root_page_no; buf_block_t* blocks[BTR_MAX_LEVELS]; ulint n_blocks; /*!< last used index in blocks[] */ @@ -3566,7 +3560,7 @@ btr_lift_page_up( to be freed.*/ block = father_block; - page = buf_block_get_frame(block); + page = block->page.frame; page_level = btr_page_get_level(page); ut_ad(!page_has_siblings(page)); @@ -3592,8 +3586,7 @@ btr_lift_page_up( ut_ad(!father_page_zip); if (page_is_leaf(page)) { - const rec_t* rec = page_rec_get_next( - page_get_infimum_rec(page)); + const rec_t* rec = page_rec_get_first(page); ut_ad(rec_is_metadata(rec, *index)); if (rec_is_add_metadata(rec, *index) && page_get_n_recs(page) == 1) { @@ -3663,9 +3656,9 @@ btr_lift_page_up( /* Go upward to root page, decrementing levels by one. */ for (i = lift_father_up ? 1 : 0; i < n_blocks; i++, page_level++) { - ut_ad(btr_page_get_level(blocks[i]->page.frame) - == page_level + 1); - btr_page_set_level(blocks[i], page_level, mtr); + page_t* page = blocks[i]->page.frame; + ut_ad(btr_page_get_level(page) == page_level + 1); + btr_page_set_level(blocks[i], page, page_level, mtr); } if (dict_index_is_spatial(index)) { @@ -3740,7 +3733,7 @@ btr_compress( ut_ad(page_is_leaf(page) || left_page_no != FIL_NULL || (REC_INFO_MIN_REC_FLAG & rec_get_info_bits( - page_rec_get_next(page_get_infimum_rec(page)), + page_rec_get_first(page), page_is_comp(page)))); heap = mem_heap_create(100); @@ -3773,7 +3766,8 @@ btr_compress( } if (adjust) { - nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); + nth_rec = page_rec_get_n_recs_before(btr_cur_get_page(cursor), + btr_cur_get_rec(cursor)); if (UNIV_UNLIKELY(!nth_rec || nth_rec == ULINT_UNDEFINED)) { corrupted: err = DB_CORRUPTION; @@ -3813,11 +3807,9 @@ btr_compress( } ut_d(leftmost_child = - left_page_no != FIL_NULL - && (page_rec_get_next( - page_get_infimum_rec( - btr_cur_get_page(&father_cursor))) - == btr_cur_get_rec(&father_cursor))); + left_page_no != FIL_NULL + && page_rec_get_first(btr_cur_get_page(&father_cursor)) + == btr_cur_get_rec(&father_cursor)); /* Decide the page to which we try to merge and which will inherit the locks */ @@ -3830,21 +3822,17 @@ btr_compress( if (!is_left && !btr_can_merge_with_page(cursor, right_page_no, &merge_block, mtr)) { - if (!merge_block) { - merge_page = NULL; - } cannot_merge: err = DB_FAIL; goto err_exit; } - merge_page = buf_block_get_frame(merge_block); + merge_page = merge_block->page.frame; if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_page + (is_left ? FIL_PAGE_NEXT : FIL_PAGE_PREV), - block->page.frame - + FIL_PAGE_OFFSET, 4))) { + page + FIL_PAGE_OFFSET, 4))) { goto corrupted; } @@ -3951,7 +3939,8 @@ btr_compress( } if (adjust) { - ulint n = page_rec_get_n_recs_before(orig_pred); + ulint n = page_rec_get_n_recs_before( + merge_page, orig_pred); if (UNIV_UNLIKELY(!n || n == ULINT_UNDEFINED)) { goto corrupted; } @@ -4043,9 +4032,8 @@ btr_compress( #ifdef UNIV_DEBUG if (!page_is_leaf(page) && left_page_no == FIL_NULL) { ut_ad(REC_INFO_MIN_REC_FLAG & rec_get_info_bits( - page_rec_get_next(page_get_infimum_rec( - buf_block_get_frame(merge_block))), - page_is_comp(page))); + page_rec_get_first(merge_page), + page_is_comp(merge_page))); } #endif /* UNIV_DEBUG */ @@ -4188,11 +4176,10 @@ btr_discard_only_page_on_level( ulint page_level = 0; ut_ad(!index->is_dummy); - + page_t* page = block->page.frame; /* Save the PAGE_MAX_TRX_ID from the leaf page. */ - const trx_id_t max_trx_id = page_get_max_trx_id(block->page.frame); - const rec_t* r = page_rec_get_next( - page_get_infimum_rec(block->page.frame)); + const trx_id_t max_trx_id = page_get_max_trx_id(page); + const rec_t* r = page_rec_get_first(page); /* In the caller we checked that a valid key exists in the page, because we were able to look up a parent page. */ ut_ad(r); @@ -4201,7 +4188,6 @@ btr_discard_only_page_on_level( while (block->page.id().page_no() != dict_index_get_page(index)) { btr_cur_t cursor; buf_block_t* father; - const page_t* page = buf_block_get_frame(block); ut_a(page_get_n_recs(page) == 1); ut_a(page_level == btr_page_get_level(page)); @@ -4237,12 +4223,13 @@ btr_discard_only_page_on_level( } block = father; + page = block->page.frame; page_level++; } /* block is the root page, which must be empty, except for the node pointer to the (now discarded) block(s). */ - ut_ad(!page_has_siblings(block->page.frame)); + ut_ad(!page_has_siblings(page)); mem_heap_t* heap = nullptr; const rec_t* rec = nullptr; @@ -4263,9 +4250,9 @@ btr_discard_only_page_on_level( } btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr); - ut_ad(page_is_leaf(buf_block_get_frame(block))); + ut_ad(page_is_leaf(page)); /* btr_page_empty() is supposed to zero-initialize the field. */ - ut_ad(!page_get_instant(block->page.frame)); + ut_ad(!page_get_instant(page)); if (index->is_primary()) { if (rec) { @@ -4286,7 +4273,7 @@ btr_discard_only_page_on_level( ibuf_reset_free_bits(block); ut_a(max_trx_id); - page_set_max_trx_id(block, + page_set_max_trx_id(block, page, buf_block_get_page_zip(block), max_trx_id, mtr); } @@ -4327,10 +4314,11 @@ btr_discard_page( } /* Decide the page which will inherit the locks */ - - const uint32_t left_page_no = btr_page_get_prev(block->page.frame); - const uint32_t right_page_no = btr_page_get_next(block->page.frame); + const page_t* const page = block->page.frame; + const uint32_t left_page_no = btr_page_get_prev(page); + const uint32_t right_page_no = btr_page_get_next(page); page_id_t merge_page_id{block->page.id()}; + page_t* merge_page; ut_d(bool parent_is_different = false); dberr_t err; @@ -4338,28 +4326,23 @@ btr_discard_page( merge_page_id.set_page_no(left_page_no); merge_block = btr_block_reget(mtr, *index, merge_page_id, &err); + merge_page = merge_block->page.frame; if (UNIV_UNLIKELY(!merge_block)) { return err; } #if 1 /* MDEV-29835 FIXME: Acquire the page latch upfront. */ - ut_ad(!memcmp_aligned<4>(merge_block->page.frame - + FIL_PAGE_NEXT, - block->page.frame + FIL_PAGE_OFFSET, - 4)); + ut_ad(!memcmp_aligned<4>(merge_page + FIL_PAGE_NEXT, + page + FIL_PAGE_OFFSET, 4)); #else - if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_block->page.frame - + FIL_PAGE_NEXT, - block->page.frame - + FIL_PAGE_OFFSET, 4))) { + if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_page + FIL_PAGE_NEXT, + page + FIL_PAGE_OFFSET, + 4))) { return DB_CORRUPTION; } #endif ut_d(parent_is_different = - (page_rec_get_next( - page_get_infimum_rec( - btr_cur_get_page( - &parent_cursor))) - == btr_cur_get_rec(&parent_cursor))); + page_rec_get_first(btr_cur_get_page(&parent_cursor)) + == btr_cur_get_rec(&parent_cursor)); } else if (right_page_no != FIL_NULL) { merge_page_id.set_page_no(right_page_no); merge_block = btr_block_reget(mtr, *index, merge_page_id, @@ -4367,26 +4350,28 @@ btr_discard_page( if (UNIV_UNLIKELY(!merge_block)) { return err; } + merge_page = merge_block->page.frame; #if 1 /* MDEV-29835 FIXME: Acquire the page latch upfront. */ - ut_ad(!memcmp_aligned<4>(merge_block->page.frame + ut_ad(!memcmp_aligned<4>(merge_page + FIL_PAGE_PREV, - block->page.frame + FIL_PAGE_OFFSET, - 4)); + page + FIL_PAGE_OFFSET, 4)); #else - if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_block->page.frame + if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_page + FIL_PAGE_PREV, - block->page.frame + page + FIL_PAGE_OFFSET, 4))) { return DB_CORRUPTION; } #endif - ut_d(parent_is_different = page_rec_is_supremum( - page_rec_get_next(btr_cur_get_rec(&parent_cursor)))); - if (page_is_leaf(merge_block->page.frame)) { - } else if (rec_t* node_ptr = - page_rec_get_next(page_get_infimum_rec( - merge_block->page.frame))) { - ut_ad(page_rec_is_user_rec(node_ptr)); + ut_d(parent_is_different = + page_rec_is_supremum( + btr_cur_get_page(&parent_cursor), + page_rec_get_next( + btr_cur_get_page(&parent_cursor), + btr_cur_get_rec(&parent_cursor)))); + if (page_is_leaf(merge_page)) { + } else if (rec_t* node_ptr = page_rec_get_first(merge_page)) { + ut_ad(page_rec_is_user_rec(merge_page, node_ptr)); /* We have to mark the leftmost node pointer as the predefined minimum record. */ btr_set_min_rec_mark(node_ptr, *merge_block, @@ -4399,9 +4384,9 @@ btr_discard_page( return DB_SUCCESS; } - if (UNIV_UNLIKELY(memcmp_aligned<2>(&merge_block->page.frame + if (UNIV_UNLIKELY(memcmp_aligned<2>(&merge_page [PAGE_HEADER + PAGE_LEVEL], - &block->page.frame + &page [PAGE_HEADER + PAGE_LEVEL], 2))) { return DB_CORRUPTION; } @@ -4423,8 +4408,7 @@ btr_discard_page( #ifdef UNIV_ZIP_DEBUG if (page_zip_des_t* merge_page_zip = buf_block_get_page_zip(merge_block)) - ut_a(page_zip_validate(merge_page_zip, - merge_block->page.frame, index)); + ut_a(page_zip_validate(merge_page_zip, merge_page, index)); #endif /* UNIV_ZIP_DEBUG */ if (index->has_locking()) { @@ -4433,7 +4417,7 @@ btr_discard_page( block); } else { lock_update_discard(merge_block, - lock_get_min_heap_no(merge_block), + lock_get_min_heap_no(merge_page), block); } @@ -4517,7 +4501,7 @@ btr_print_recursive( rec_offs** offsets,/*!< in/out: buffer for rec_get_offsets() */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page = buf_block_get_frame(block); + const page_t* page = block->page.frame; page_cur_t cursor; ulint n_recs; ulint i = 0; @@ -4615,7 +4599,7 @@ btr_check_node_ptr( dtuple_t* tuple; rec_offs* offsets; btr_cur_t cursor; - page_t* page = buf_block_get_frame(block); + page_t* page = block->page.frame; ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); @@ -4644,7 +4628,7 @@ btr_check_node_ptr( } tuple = dict_index_build_node_ptr( - index, page_rec_get_next(page_get_infimum_rec(page)), 0, heap, + index, page_rec_get_first(page), 0, heap, btr_page_get_level(page)); /* For spatial index, the MBR in the parent rec could be different @@ -4666,7 +4650,7 @@ btr_check_node_ptr( /************************************************************//** Display identification information for a record. */ -static +static ATTRIBUTE_COLD void btr_index_rec_validate_report( /*==========================*/ @@ -4678,31 +4662,30 @@ btr_index_rec_validate_report( << " of table " << index->table->name << ", page " << page_id_t(page_get_space_id(page), page_get_page_no(page)) - << ", at offset " << page_offset(rec); + << ", at offset " << rec - page; } /************************************************************//** Checks the size and number of fields in a record based on the definition of the index. @return TRUE if ok */ -ibool +bool btr_index_rec_validate( /*===================*/ + const page_t* page, /*!< in: index page */ const rec_t* rec, /*!< in: index record */ const dict_index_t* index, /*!< in: index */ - ibool dump_on_error) /*!< in: TRUE if the function + bool dump_on_error) /*!< in: TRUE if the function should print hex dump of record and page on error */ { ulint len; - const page_t* page; mem_heap_t* heap = NULL; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; rec_offs_init(offsets_); - page = page_align(rec); - + ut_ad(page == page_align(rec)); ut_ad(index->n_core_fields); if (index->is_ibuf()) { @@ -4710,7 +4693,7 @@ btr_index_rec_validate( other index: we cannot check the number of fields or their length */ - return(TRUE); + return true; } #ifdef VIRTUAL_INDEX_DEBUG @@ -4724,20 +4707,20 @@ btr_index_rec_validate( ib::error() << "Compact flag=" << !!page_is_comp(page) << ", should be " << dict_table_is_comp(index->table); - return(FALSE); + return false; } const bool is_alter_metadata = page_is_leaf(page) && !page_has_prev(page) && index->is_primary() && index->table->instant - && rec == page_rec_get_next_const(page_get_infimum_rec(page)); + && page_rec_is_first(page, rec); if (is_alter_metadata && !rec_is_alter_metadata(rec, page_is_comp(page))) { btr_index_rec_validate_report(page, rec, index); ib::error() << "First record is not ALTER TABLE metadata"; - return FALSE; + return false; } if (!page_is_comp(page)) { @@ -4765,7 +4748,7 @@ btr_index_rec_validate( rec_print_old(stderr, rec); putc('\n', stderr); } - return(FALSE); + return false; } } @@ -4832,7 +4815,7 @@ btr_index_rec_validate( if (heap) { mem_heap_free(heap); } - return(FALSE); + return false; } next_field: field++; @@ -4847,7 +4830,7 @@ btr_index_rec_validate( if (heap) { mem_heap_free(heap); } - return(TRUE); + return true; } /************************************************************//** @@ -4874,6 +4857,7 @@ btr_index_page_validate( page_cur_get_page(&cur), 0) == cur.rec); ut_a(page_dir_slot_get_n_owned( + page_cur_get_page(&cur), page_dir_get_nth_slot( page_cur_get_page(&cur), 0)) == 1);); @@ -4883,7 +4867,8 @@ btr_index_page_validate( return true; } - if (!btr_index_rec_validate(cur.rec, index, TRUE)) { + if (!btr_index_rec_validate(block->page.frame, + cur.rec, index, true)) { break; } @@ -4893,8 +4878,10 @@ btr_index_page_validate( ut_a(cur.rec == page_rec_get_nth_const( page_cur_get_page(&cur), page_rec_get_n_recs_before( + page_cur_get_page(&cur), cur.rec))); ut_a(nth++ == page_rec_get_n_recs_before( + page_cur_get_page(&cur), cur.rec));); } @@ -4978,7 +4965,7 @@ btr_validate_level( mtr.commit(); return err; } - page = buf_block_get_frame(block); + page = block->page.frame; fil_space_t* space = index->table->space; @@ -5022,7 +5009,7 @@ btr_validate_level( if (!block) { break; } - page = buf_block_get_frame(block); + page = block->page.frame; /* For R-Tree, since record order might not be the same as linked index page in the lower level, we need to travers @@ -5045,7 +5032,7 @@ btr_validate_level( if (!block) { goto invalid_page; } - page = buf_block_get_frame(block); + page = block->page.frame; left_page_no = btr_page_get_prev(page); } } @@ -5118,7 +5105,7 @@ btr_validate_level( fputs("InnoDB: broken FIL_PAGE_NEXT link\n", stderr); goto invalid_page; } - right_page = buf_block_get_frame(right_block); + right_page = right_block->page.frame; if (btr_page_get_prev(right_page) != page_get_page_no(page)) { btr_validate_report2(index, level, block, right_block); @@ -5127,14 +5114,14 @@ btr_validate_level( err = DB_CORRUPTION; } - if (!(rec = page_rec_get_prev(page_get_supremum_rec(page)))) { + rec = page_rec_get_prev(page, page_get_supremum_rec(page)); + if (!rec) { broken_links: btr_validate_report1(index, level, block); fputs("InnoDB: broken record links\n", stderr); goto invalid_page; } - if (!(right_rec = - page_rec_get_next(page_get_infimum_rec(right_page)))) { + if (!(right_rec = page_rec_get_first(right_page))) { goto broken_links; } @@ -5159,15 +5146,14 @@ btr_validate_level( fputs("InnoDB: records in wrong order" " on adjacent pages\n", stderr); - rec = page_rec_get_prev(page_get_supremum_rec(page)); + rec = page_rec_get_prev(page, page_get_supremum_rec(page)); if (rec) { fputs("InnoDB: record ", stderr); rec_print(stderr, rec, index); putc('\n', stderr); } fputs("InnoDB: record ", stderr); - rec = page_rec_get_next( - page_get_infimum_rec(right_page)); + rec = page_rec_get_first(right_page); if (rec) { rec_print(stderr, rec, index); } @@ -5177,8 +5163,7 @@ btr_validate_level( } if (!level || left_page_no != FIL_NULL) { - } else if (const rec_t* first = - page_rec_get_next_const(page_get_infimum_rec(page))) { + } else if (const rec_t* first = page_rec_get_first(page)) { if (!(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(first, page_is_comp(page)))) { btr_validate_report1(index, level, block); @@ -5199,8 +5184,7 @@ btr_validate_level( if (!index->is_spatial() && block->page.id().page_no() != index->page) { /* Check father node pointers */ - rec_t* node_ptr - = page_rec_get_next(page_get_infimum_rec(page)); + rec_t* node_ptr = page_rec_get_first(page); if (!node_ptr) { err = DB_CORRUPTION; goto node_ptr_fails; @@ -5213,7 +5197,7 @@ btr_validate_level( father_page = btr_cur_get_page(&node_cur); node_ptr = btr_cur_get_rec(&node_cur); - rec = page_rec_get_prev(page_get_supremum_rec(page)); + rec = page_rec_get_prev(page, page_get_supremum_rec(page)); if (rec) { btr_cur_position(index, rec, block, &node_cur); @@ -5251,8 +5235,7 @@ btr_validate_level( } if (page_is_leaf(page)) { - } else if (const rec_t* first_rec = - page_rec_get_next(page_get_infimum_rec(page))) { + } else if (const rec_t* first_rec = page_rec_get_first(page)) { node_ptr_tuple = dict_index_build_node_ptr( index, first_rec, 0, heap, btr_page_get_level(page)); @@ -5278,8 +5261,7 @@ btr_validate_level( if (left_page_no == FIL_NULL) { if (page_has_prev(father_page) - || node_ptr != page_rec_get_next( - page_get_infimum_rec(father_page))) { + || !page_rec_is_first(father_page, node_ptr)) { err = DB_CORRUPTION; goto node_ptr_fails; } @@ -5287,16 +5269,15 @@ btr_validate_level( if (right_page_no == FIL_NULL) { if (page_has_next(father_page) - || node_ptr != page_rec_get_prev( - page_get_supremum_rec(father_page))) { + || !page_rec_is_last(father_page, node_ptr)) { err = DB_CORRUPTION; goto node_ptr_fails; } } else if (const rec_t* right_node_ptr - = page_rec_get_next(node_ptr)) { + = page_rec_get_next(father_page, node_ptr)) { btr_cur_position( index, - page_get_infimum_rec(right_block->page.frame), + page_get_infimum_rec(right_page), right_block, &right_node_cur); if (!page_cur_move_to_next(&right_node_cur.page_cur)) { goto node_pointer_corrupted; @@ -5324,9 +5305,7 @@ btr_validate_level( = btr_cur_get_page(&right_node_cur); if (btr_cur_get_rec(&right_node_cur) - != page_rec_get_next( - page_get_infimum_rec( - right_father_page))) { + != page_rec_get_first(right_father_page)) { err = DB_CORRUPTION; fputs("InnoDB: node pointer 2 to" " the right page is wrong\n", @@ -5438,7 +5417,7 @@ btr_can_merge_with_page( if (!mblock) { goto error; } - mpage = buf_block_get_frame(mblock); + mpage = mblock->page.frame; n_recs = page_get_n_recs(page); data_size = page_get_data_size(page); diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 5dcd19fec6486..cd2bc29b57b19 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -70,7 +70,7 @@ PageBulk::init() return err; } - new_page = buf_block_get_frame(new_block); + new_page = new_block->page.frame; m_page_no = new_block->page.id().page_no(); byte* index_id = my_assume_aligned<2> @@ -101,11 +101,11 @@ PageBulk::init() return(DB_CORRUPTION); } - new_page = buf_block_get_frame(new_block); + new_page = new_block->page.frame; ut_ad(page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW); - btr_page_set_level(new_block, m_level, &m_mtr); + btr_page_set_level(new_block, new_page, m_level, &m_mtr); } m_page_zip = buf_block_get_page_zip(new_block); @@ -162,10 +162,10 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) #ifdef UNIV_DEBUG /* Check whether records are in order. */ - if (page_offset(m_cur_rec) != + if (m_cur_rec - m_page != (fmt == REDUNDANT ? PAGE_OLD_INFIMUM : PAGE_NEW_INFIMUM)) { - const rec_t *old_rec = m_cur_rec; + const rec_t *old_rec= m_cur_rec; rec_offs *old_offsets= rec_get_offsets(old_rec, m_index, nullptr, is_leaf ? m_index->n_core_fields : 0, ULINT_UNDEFINED, &m_heap); @@ -180,8 +180,7 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) /* Insert the record in the linked list. */ if (fmt != REDUNDANT) { - const rec_t *next_rec= m_page + - page_offset(m_cur_rec + mach_read_from_2(m_cur_rec - REC_NEXT)); + const rec_t *next_rec= m_cur_rec + mach_read_from_2(m_cur_rec - REC_NEXT); if (fmt != COMPRESSED) m_mtr.write<2>(*m_block, m_cur_rec - REC_NEXT, static_cast(insert_rec - m_cur_rec)); @@ -204,7 +203,7 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) else { memcpy(const_cast(rec) - REC_NEXT, m_cur_rec - REC_NEXT, 2); - m_mtr.write<2>(*m_block, m_cur_rec - REC_NEXT, page_offset(insert_rec)); + m_mtr.write<2>(*m_block, m_cur_rec - REC_NEXT, insert_rec - m_page); rec_set_bit_field_1(const_cast(rec), 0, REC_OLD_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); rec_set_bit_field_2(const_cast(rec), @@ -214,7 +213,7 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) if (fmt == COMPRESSED) /* We already wrote the record. Log is written in PageBulk::compress(). */; - else if (page_offset(m_cur_rec) == + else if (m_cur_rec - m_page == (fmt == REDUNDANT ? PAGE_OLD_INFIMUM : PAGE_NEW_INFIMUM)) m_mtr.memcpy(*m_block, m_heap_top, rec - extra_size, rec_size); else @@ -246,7 +245,7 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) if (len > 2) { memcpy(b, c, len); - m_mtr.memmove(*m_block, page_offset(b), page_offset(c), len); + m_mtr.memmove(*m_block, b, c, len); c= cm; b= bm; r= rm; @@ -285,7 +284,7 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) { m_mtr.memcpy(*m_block, b, r, m_cur_rec - c); memcpy(bd, cd, len); - m_mtr.memmove(*m_block, page_offset(bd), page_offset(cd), len); + m_mtr.memmove(*m_block, bd, cd, len); c= cdm; b= rdm - rd + bd; r= rdm; @@ -401,7 +400,7 @@ inline void PageBulk::finishPage() /* Merge the last two slots, like page_cur_insert_rec_low() does. */ count+= (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2; - rec_t *rec= const_cast(page_dir_slot_get_rec(slot)); + rec_t *rec= const_cast(page_dir_slot_get_rec(m_page, slot)); if (fmt != COMPRESSED) page_rec_set_n_owned(m_block, rec, 0, true, &m_mtr); else @@ -430,7 +429,7 @@ inline void PageBulk::finishPage() if (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2) { slot-= PAGE_DIR_SLOT_SIZE; - mach_write_to_2(slot, page_offset(insert_rec)); + mach_write_to_2(slot, insert_rec - m_page); page_rec_set_n_owned(m_block, insert_rec, count, false, &m_mtr); count= 0; } @@ -444,7 +443,7 @@ inline void PageBulk::finishPage() /* Merge the last two slots, like page_cur_insert_rec_low() does. */ count+= (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2; - rec_t *rec= const_cast(page_dir_slot_get_rec(slot)); + rec_t *rec= const_cast(page_dir_slot_get_rec(m_page, slot)); page_rec_set_n_owned(m_block, rec, 0, false, &m_mtr); } else @@ -469,7 +468,7 @@ inline void PageBulk::finishPage() m_mtr.memcpy(*m_block, PAGE_HEADER + m_page, page_header, sizeof page_header); m_mtr.write<2>(*m_block, PAGE_HEADER + PAGE_N_RECS + m_page, m_rec_no); - m_mtr.memcpy(*m_block, page_offset(slot), slot0 - slot); + m_mtr.memcpy(*m_block, slot, slot0 - slot); } else { @@ -577,8 +576,7 @@ PageBulk::getNodePtr() dtuple_t* node_ptr; /* Create node pointer */ - first_rec = page_rec_get_next(page_get_infimum_rec(m_page)); - ut_a(page_rec_is_user_rec(first_rec)); + first_rec = page_rec_get_first(m_page); node_ptr = dict_index_build_node_ptr(m_index, first_rec, m_page_no, m_heap, m_level); @@ -612,8 +610,8 @@ PageBulk::getSplitRec() const ulint n_core = page_is_leaf(m_page) ? m_index->n_core_fields : 0; do { - rec = page_rec_get_next(rec); - ut_ad(page_rec_is_user_rec(rec)); + rec = page_rec_get_next(m_page, rec); + ut_ad(page_rec_is_user_rec(m_page, rec)); offsets = rec_get_offsets(rec, m_index, offsets, n_core, ULINT_UNDEFINED, &m_heap); @@ -623,28 +621,23 @@ PageBulk::getSplitRec() < total_used_size / 2); /* Keep at least one record on left page */ - if (page_rec_is_first(rec, m_page)) { - rec = page_rec_get_next(rec); - ut_ad(page_rec_is_user_rec(rec)); + if (page_rec_is_first(m_page, rec)) { + rec = page_rec_get_next(m_page, rec); + ut_ad(page_rec_is_user_rec(m_page, rec)); } return(rec); } -/** Copy all records after split rec including itself. -@param[in] rec split rec */ -void -PageBulk::copyIn( - rec_t* split_rec) +void PageBulk::copyIn(const page_t *page, const rec_t *rec) { - rec_t* rec = split_rec; rec_offs* offsets = NULL; ut_ad(m_rec_no == 0); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); - const ulint n_core = page_rec_is_leaf(rec) + const ulint n_core = page_is_leaf(page) ? m_index->n_core_fields : 0; do { @@ -653,17 +646,13 @@ PageBulk::copyIn( insert(rec, offsets); - rec = page_rec_get_next(rec); - } while (!page_rec_is_supremum(rec)); + rec = page_rec_get_next(page, rec); + } while (!page_rec_is_supremum(page, rec)); ut_ad(m_rec_no > 0); } -/** Remove all records after split rec including itself. -@param[in] rec split rec */ -void -PageBulk::copyOut( - rec_t* split_rec) +inline void PageBulk::copyOut(rec_t *split_rec) { /* Suppose before copyOut, we have 5 records on the page: infimum->r1->r2->r3->r4->r5->supremum, and r3 is the split rec. @@ -675,7 +664,7 @@ PageBulk::copyOut( ulint n; for (n = 0;; n++) { - rec_t *next = page_rec_get_next(rec); + rec_t *next = page_rec_get_next(m_page, rec); if (next == split_rec) { break; } @@ -684,24 +673,23 @@ PageBulk::copyOut( ut_ad(n > 0); - const rec_t *last_rec = split_rec; + const rec_t *last_rec = split_rec; for (;;) { - const rec_t *next = page_rec_get_next_const(last_rec); - if (page_rec_is_supremum(next)) { + const rec_t *next = page_rec_get_next(m_page, last_rec); + if (page_rec_is_supremum(m_page, next)) { break; } last_rec = next; } /* Set last record's next in page */ - const ulint n_core = page_rec_is_leaf(split_rec) + const ulint n_core = page_is_leaf(m_page) ? m_index->n_core_fields : 0; rec_offs* offsets = rec_get_offsets(rec, m_index, nullptr, n_core, ULINT_UNDEFINED, &m_heap); mach_write_to_2(rec - REC_NEXT, m_is_comp - ? static_cast - (PAGE_NEW_SUPREMUM - page_offset(rec)) + ? uint16_t(PAGE_NEW_SUPREMUM - (rec - m_page)) : PAGE_OLD_SUPREMUM); /* Set related members */ @@ -883,7 +871,7 @@ BtrBulk::pageSplit( /* Copy the upper half to the new page. */ rec_t* split_rec = page_bulk->getSplitRec(); - new_page_bulk.copyIn(split_rec); + new_page_bulk.copyIn(page_bulk->getPage(), split_rec); page_bulk->copyOut(split_rec); /* Commit the pages after split. */ @@ -1190,19 +1178,18 @@ BtrBulk::finish(dberr_t err) return err; } - first_rec = page_rec_get_next( - page_get_infimum_rec(last_block->page.frame)); + page_t* last_page = last_block->page.frame; + first_rec = page_rec_get_first(last_page); /* Because this index tree is being created by this thread, we assume that it cannot be corrupted. */ ut_ad(first_rec); - ut_ad(page_rec_is_user_rec(first_rec)); /* Copy last page to root page. */ err = root_page_bulk.init(); if (err != DB_SUCCESS) { goto err_exit; } - root_page_bulk.copyIn(first_rec); + root_page_bulk.copyIn(last_page, first_rec); root_page_bulk.finish(); /* Remove last page. */ diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index cff9e664c5d52..f11255c769e57 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -213,13 +213,15 @@ static dberr_t btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) goto unreadable; } - if (btr_cur_instant_root_init(index, root->page.frame)) { + const page_t* const r = root->page.frame; + + if (btr_cur_instant_root_init(index, r)) { goto corrupted; } ut_ad(index->n_core_null_bytes != dict_index_t::NO_CORE_NULL_BYTES); - if (fil_page_get_type(root->page.frame) == FIL_PAGE_INDEX) { + if (fil_page_get_type(r) == FIL_PAGE_INDEX) { ut_ad(!index->is_instant()); return DB_SUCCESS; } @@ -237,13 +239,13 @@ static dberr_t btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) } ut_ad(page_cur_is_before_first(&cur.page_cur)); - ut_ad(page_is_leaf(cur.page_cur.block->page.frame)); + ut_ad(page_is_leaf(page_align(cur.page_cur.rec))); const rec_t* rec = page_cur_move_to_next(&cur.page_cur); const ulint comp = dict_table_is_comp(index->table); const ulint info_bits = rec ? rec_get_info_bits(rec, comp) : 0; - if (page_rec_is_supremum(rec) + if (page_rec_is_supremum(btr_cur_get_page(&cur), rec) || !(info_bits & REC_INFO_MIN_REC_FLAG)) { if (rec && !index->is_instant()) { /* The FIL_PAGE_TYPE_INSTANT and PAGE_INSTANT may be @@ -364,22 +366,22 @@ static dberr_t btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) goto incompatible; } - if (fil_page_get_type(block->page.frame) != FIL_PAGE_TYPE_BLOB - || mach_read_from_4(&block->page.frame - [FIL_PAGE_DATA - + BTR_BLOB_HDR_NEXT_PAGE_NO]) + const page_t* const page = block->page.frame; + + if (fil_page_get_type(page) != FIL_PAGE_TYPE_BLOB + || mach_read_from_4(&page[FIL_PAGE_DATA + + BTR_BLOB_HDR_NEXT_PAGE_NO]) != FIL_NULL - || mach_read_from_4(&block->page.frame - [FIL_PAGE_DATA - + BTR_BLOB_HDR_PART_LEN]) + || mach_read_from_4(&page[FIL_PAGE_DATA + + BTR_BLOB_HDR_PART_LEN]) != len) { goto incompatible; } /* The unused part of the BLOB page should be zero-filled. */ - for (const byte* b = block->page.frame + for (const byte* b = page + (FIL_PAGE_DATA + BTR_BLOB_HDR_SIZE) + len, - * const end = block->page.frame + srv_page_size + * const end = page + srv_page_size - BTR_EXTERN_LEN; b < end; ) { if (*b++) { @@ -388,8 +390,7 @@ static dberr_t btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) } if (index->table->deserialise_columns( - &block->page.frame - [FIL_PAGE_DATA + BTR_BLOB_HDR_SIZE], len)) { + &page[FIL_PAGE_DATA + BTR_BLOB_HDR_SIZE], len)) { goto incompatible; } @@ -592,13 +593,14 @@ btr_intention_t btr_cur_get_and_clear_intention(btr_latch_mode *latch_mode) /** @return whether the distance between two records is at most the specified value */ static bool -page_rec_distance_is_at_most(const rec_t *left, const rec_t *right, ulint val) +page_rec_distance_is_at_most(const page_t *page, + const rec_t *left, const rec_t *right, ulint val) { do { if (left == right) return true; - left= page_rec_get_next_const(left); + left= page_rec_get_next(page, left); } while (left && val--); return false; @@ -670,7 +672,7 @@ btr_cur_will_modify_tree( /* check delete will cause. (BTR_INTENTION_BOTH or BTR_INTENTION_DELETE) */ if (n_recs <= max_nodes_deleted * 2 - || page_rec_is_first(rec, page)) { + || page_rec_is_first(page, rec)) { /* The cursor record can be the left most record in this page. */ return true; @@ -678,14 +680,14 @@ btr_cur_will_modify_tree( if (page_has_prev(page) && page_rec_distance_is_at_most( - page_get_infimum_rec(page), rec, + page, page_get_infimum_rec(page), rec, max_nodes_deleted)) { return true; } if (page_has_next(page) && page_rec_distance_is_at_most( - rec, page_get_supremum_rec(page), + page, rec, page_get_supremum_rec(page), max_nodes_deleted)) { return true; } @@ -765,13 +767,13 @@ static bool btr_cur_need_opposite_intention(const buf_page_t &bpage, { /* We compensate also for btr_cur_compress_recommendation() */ if (!page_has_siblings(page) || - page_rec_is_first(rec, page) || page_rec_is_last(rec, page) || + page_rec_is_first(page, rec) || page_rec_is_last(page, rec) || page_get_data_size(page) < node_ptr_max_size + compress_limit) return true; if (lock_intention == BTR_INTENTION_DELETE) return false; } - else if (page_has_next(page) && page_rec_is_last(rec, page)) + else if (page_has_next(page) && page_rec_is_last(page, rec)) return true; LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page), return true); const ulint max_size= page_get_max_insert_size_after_reorganize(page, 2); @@ -1290,10 +1292,12 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, goto search_loop; } - if (!!page_is_comp(block->page.frame) != index()->table->not_redundant() || - btr_page_get_index_id(block->page.frame) != index()->id || - fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE || - !fil_page_index_page_check(block->page.frame)) + const page_t *const page= block->page.frame; + + if (!!page_is_comp(page) != index()->table->not_redundant() || + btr_page_get_index_id(page) != index()->id || + fil_page_get_type(page) == FIL_PAGE_RTREE || + !fil_page_index_page_check(page)) goto corrupted; page_cur.block= block; @@ -1301,10 +1305,10 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, const bool not_first_access{buf_page_make_young_if_needed(&block->page)}; #ifdef UNIV_ZIP_DEBUG if (const page_zip_des_t *page_zip= buf_block_get_page_zip(block)) - ut_a(page_zip_validate(page_zip, block->page.frame, index())); + ut_a(page_zip_validate(page_zip, page, index())); #endif /* UNIV_ZIP_DEBUG */ - const uint32_t page_level= btr_page_get_level(block->page.frame); + const uint32_t page_level= btr_page_get_level(page); if (height == ULINT_UNDEFINED) { @@ -1406,11 +1410,11 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, rw_lock_type_t(latch_mode & (RW_X_LATCH | RW_S_LATCH))); /* latch also siblings from left to right */ - if (page_has_prev(block->page.frame) && + if (page_has_prev(page) && !btr_latch_prev(block, page_id, zip_size, rw_latch, mtr, &err)) goto func_exit; - if (page_has_next(block->page.frame) && - !btr_block_get(*index(), btr_page_get_next(block->page.frame), + if (page_has_next(page) && + !btr_block_get(*index(), btr_page_get_next(page), rw_latch, false, mtr, &err)) goto func_exit; goto release_tree; @@ -1431,11 +1435,11 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, ut_ad(latch_mode == BTR_MODIFY_TREE); ut_ad(rw_latch == RW_X_LATCH); /* x-latch also siblings from left to right */ - if (page_has_prev(block->page.frame) && + if (page_has_prev(page) && !btr_latch_prev(block, page_id, zip_size, rw_latch, mtr, &err)) goto func_exit; - if (page_has_next(block->page.frame) && - !btr_block_get(*index(), btr_page_get_next(block->page.frame), + if (page_has_next(page) && + !btr_block_get(*index(), btr_page_get_next(page), RW_X_LATCH, false, mtr, &err)) goto func_exit; } @@ -1464,7 +1468,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) - goto need_opposite_intention; + goto need_opposite_intention; #ifdef BTR_CUR_HASH_ADAPT /* We do a dirty read of btr_search_enabled here. We will @@ -1518,14 +1522,12 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, be chosen when BTR_CONT_MODIFY_TREE. So, the parent page should not released to avoiding deadlock with blocking the another search with the same key value. */ - const rec_t *first= - page_rec_get_next_const(page_get_infimum_rec(block->page.frame)); + const rec_t *first= page_rec_get_first(page); ulint matched_fields; if (UNIV_UNLIKELY(!first)) goto corrupted; - if (page_cur.rec == first || - page_rec_is_last(page_cur.rec, block->page.frame)) + if (page_cur.rec == first || page_rec_is_last(page, page_cur.rec)) { same_key_root: detected_same_key_root= true; @@ -1540,7 +1542,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, if (matched_fields >= rec_offs_n_fields(offsets) - 1) goto same_key_root; if (const rec_t* last= - page_rec_get_prev_const(page_get_supremum_rec(block->page.frame))) + page_rec_get_prev(page, page_get_supremum_rec(page))) { matched_fields= 0; offsets2= rec_get_offsets(last, index(), offsets2, 0, ULINT_UNDEFINED, @@ -1555,7 +1557,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, /* Release the non-root parent page unless it may need to be modified. */ if (tree_height > height + 1 && - !btr_cur_will_modify_tree(index(), block->page.frame, lock_intention, + !btr_cur_will_modify_tree(index(), page, lock_intention, page_cur.rec, node_ptr_max_size, zip_size, mtr)) { @@ -1582,8 +1584,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, if (!not_first_access) buf_read_ahead_linear(page_id, zip_size, false); - if (page_has_prev(block->page.frame) && - page_rec_is_first(page_cur.rec, block->page.frame)) + if (page_has_prev(page) && page_rec_is_first(page, page_cur.rec)) { ut_ad(block_savepoint + 1 == mtr->get_savepoint()); @@ -1628,8 +1629,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, ut_ad(rw_latch == RW_X_LATCH); if (lock_intention == BTR_INTENTION_INSERT && - page_has_next(block->page.frame) && - page_rec_is_last(page_cur.rec, block->page.frame)) + page_has_next(page) && page_rec_is_last(page, page_cur.rec)) { /* btr_insert_into_right_sibling() might cause deleting node_ptr at upper level */ @@ -1692,7 +1692,9 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple, up_bytes= 0; low_match= 0; low_bytes= 0; - ulint height= btr_page_get_level(block->page.frame); + + const page_t *page= block->page.frame; + ulint height= btr_page_get_level(page); tree_height= height + 1; mem_heap_t *heap= nullptr; @@ -1757,28 +1759,30 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple, goto func_exit; } - if (!!page_is_comp(block->page.frame) != index()->table->not_redundant() || - btr_page_get_index_id(block->page.frame) != index()->id || - fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE || - !fil_page_index_page_check(block->page.frame)) + page= block->page.frame; + + if (!!page_is_comp(page) != index()->table->not_redundant() || + btr_page_get_index_id(page) != index()->id || + fil_page_get_type(page) == FIL_PAGE_RTREE || + !fil_page_index_page_check(page)) goto corrupted; - if (height != btr_page_get_level(block->page.frame)) + if (height != btr_page_get_level(page)) goto corrupted; btr_cur_nonleaf_make_young(&block->page); #ifdef UNIV_ZIP_DEBUG const page_zip_des_t *page_zip= buf_block_get_page_zip(block); - ut_a(!page_zip || page_zip_validate(page_zip, block->page.frame, index())); + ut_a(!page_zip || page_zip_validate(page_zip, page, index())); #endif /* UNIV_ZIP_DEBUG */ - if (page_has_prev(block->page.frame) && + if (page_has_prev(page) && !btr_latch_prev(block, page_id, block->zip_size(), RW_X_LATCH, mtr, &err)) goto func_exit; - if (page_has_next(block->page.frame) && - !btr_block_get(*index(), btr_page_get_next(block->page.frame), + if (page_has_next(page) && + !btr_block_get(*index(), btr_page_get_next(page), RW_X_LATCH, false, mtr, &err)) goto func_exit; goto search_loop; @@ -1844,6 +1848,7 @@ dberr_t btr_cur_search_to_nth_level(ulint level, search_loop: dberr_t err= DB_SUCCESS; + const page_t *page; if (buf_block_t *b= mtr->get_already_latched(page_id, mtr_memo_type_t(rw_latch))) block= b; @@ -1857,15 +1862,16 @@ dberr_t btr_cur_search_to_nth_level(ulint level, else btr_cur_nonleaf_make_young(&block->page); + page= block->page.frame; #ifdef UNIV_ZIP_DEBUG if (const page_zip_des_t *page_zip= buf_block_get_page_zip(block)) - ut_a(page_zip_validate(page_zip, block->page.frame, index)); + ut_a(page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ - if (!!page_is_comp(block->page.frame) != index->table->not_redundant() || - btr_page_get_index_id(block->page.frame) != index->id || - fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE || - !fil_page_index_page_check(block->page.frame)) + if (!!page_is_comp(page) != index->table->not_redundant() || + btr_page_get_index_id(page) != index->id || + fil_page_get_type(page) == FIL_PAGE_RTREE || + !fil_page_index_page_check(page)) { corrupted: err= DB_CORRUPTION; @@ -1875,7 +1881,7 @@ dberr_t btr_cur_search_to_nth_level(ulint level, return err; } - const uint32_t page_level= btr_page_get_level(block->page.frame); + const uint32_t page_level= btr_page_get_level(page); if (height == ULINT_UNDEFINED) { @@ -2006,7 +2012,8 @@ dberr_t btr_cur_t::open_leaf(bool first, dict_index_t *index, else page_cur_set_after_last(block, &page_cur); - const uint32_t l= btr_page_get_level(block->page.frame); + const page_t *const p= page_cur_get_page(&page_cur); + const uint32_t l= btr_page_get_level(p); if (height == ULINT_UNDEFINED) { @@ -2034,12 +2041,12 @@ dberr_t btr_cur_t::open_leaf(bool first, dict_index_t *index, if (latch_mode == BTR_MODIFY_TREE) { /* x-latch also siblings from left to right */ - if (page_has_prev(block->page.frame) && + if (page_has_prev(p) && !btr_latch_prev(block, block->page.id(), zip_size, RW_X_LATCH, mtr, &err)) break; - if (page_has_next(block->page.frame) && - !btr_block_get(*index, btr_page_get_next(block->page.frame), + if (page_has_next(p) && + !btr_block_get(*index, btr_page_get_next(p), RW_X_LATCH, false, mtr, &err)) break; @@ -2114,8 +2121,7 @@ dberr_t btr_cur_t::open_leaf(bool first, dict_index_t *index, } else { - if (!btr_cur_will_modify_tree(index, block->page.frame, - lock_intention, page_cur.rec, + if (!btr_cur_will_modify_tree(index, p, lock_intention, page_cur.rec, node_ptr_max_size, zip_size, mtr)) { ut_ad(n_blocks); @@ -2278,7 +2284,7 @@ btr_cur_ins_lock_and_undo( } } - if (!index->is_primary() || !page_is_leaf(page_align(rec))) { + if (!index->is_primary() || !page_rec_is_leaf(rec)) { return DB_SUCCESS; } @@ -2318,12 +2324,13 @@ Prefetch siblings of the leaf for the pessimistic operation. static void btr_cur_prefetch_siblings(const buf_block_t *block, const dict_index_t *index) { - ut_ad(page_is_leaf(block->page.frame)); + const page_t *page= block->page.frame; + + ut_ad(page_is_leaf(page)); if (index->is_ibuf()) return; - const page_t *page= block->page.frame; uint32_t prev= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_PREV)); uint32_t next= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_NEXT)); @@ -2389,7 +2396,7 @@ btr_cur_optimistic_insert( *big_rec = NULL; block = btr_cur_get_block(cursor); - page = buf_block_get_frame(block); + page = btr_cur_get_page(cursor); index = cursor->index(); ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); @@ -2746,11 +2753,13 @@ btr_cur_pessimistic_insert( : btr_page_split_and_insert(flags, cursor, offsets, heap, entry, n_ext, mtr, &err); + const page_t *const page = btr_cur_get_page(cursor); + if (!*rec) { goto func_exit; } - ut_ad(page_rec_get_next(btr_cur_get_rec(cursor)) == *rec + ut_ad(page_rec_get_next(page, btr_cur_get_rec(cursor)) == *rec || dict_index_is_spatial(index)); if (!(flags & BTR_NO_LOCKING_FLAG)) { @@ -2768,8 +2777,9 @@ btr_cur_pessimistic_insert( thr_get_trx(thr)->id, mtr); } - if (!page_rec_is_infimum(btr_cur_get_rec(cursor)) - || !page_has_prev(btr_cur_get_page(cursor))) { + if (!page_has_prev(page) + || !page_rec_is_infimum(page, + btr_cur_get_rec(cursor))) { /* split and inserted need to call lock_update_insert() always. */ inherit = true; @@ -2777,7 +2787,7 @@ btr_cur_pessimistic_insert( } } - if (!page_is_leaf(btr_cur_get_page(cursor))) { + if (!page_is_leaf(page)) { ut_ad(!big_rec_vec); } else { #ifdef BTR_CUR_HASH_ADAPT @@ -2940,10 +2950,11 @@ static dberr_t btr_cur_upd_rec_sys(buf_block_t *block, rec_t *rec, if (UNIV_LIKELY(index->trx_id_offset)) { - const rec_t *prev= page_rec_get_prev_const(rec); + const page_t *const page= block->page.frame; + const rec_t *prev= page_rec_get_prev(page, rec); if (UNIV_UNLIKELY(!prev || prev == rec)) return DB_CORRUPTION; - else if (page_rec_is_infimum(prev)); + else if (page_rec_is_infimum(page, prev)); else for (src= prev + offset; d < DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN; d++) if (src[d] != sys[d]) @@ -2967,7 +2978,7 @@ static dberr_t btr_cur_upd_rec_sys(buf_block_t *block, rec_t *rec, To save space, we must have d>6, that is, the complete DB_TRX_ID and the first byte(s) of DB_ROLL_PTR must match the previous record. */ memcpy(dest, src, d); - mtr->memmove(*block, page_offset(dest), page_offset(src), d); + mtr->memmove(*block, dest, src, d); dest+= d; len-= d; /* DB_TRX_ID,DB_ROLL_PTR must be unique in each record when @@ -3155,8 +3166,7 @@ void btr_cur_upd_rec_in_place(rec_t *rec, const dict_index_t *index, default: mtr->memset( block, - page_offset(rec_get_field_start_offs( - rec, n) + rec), + rec_get_field_start_offs(rec, n) + rec, size, 0); } ulint l = rec_get_1byte_offs_flag(rec) @@ -3308,7 +3318,7 @@ btr_cur_update_in_place( roll_ptr_t roll_ptr = 0; ulint was_delete_marked; - ut_ad(page_is_leaf(cursor->page_cur.block->page.frame)); + ut_ad(page_is_leaf(btr_cur_get_page(cursor))); rec = btr_cur_get_rec(cursor); index = cursor->index(); ut_ad(!index->is_ibuf()); @@ -3362,8 +3372,8 @@ btr_cur_update_in_place( } } - was_delete_marked = rec_get_deleted_flag( - rec, page_is_comp(buf_block_get_frame(block))); + was_delete_marked + = rec_get_deleted_flag(rec, page_is_comp(block->page.frame)); /* In delete-marked records, DB_TRX_ID must always refer to an existing undo log record. */ ut_ad(!was_delete_marked @@ -3409,8 +3419,7 @@ btr_cur_update_in_place( #endif /* BTR_CUR_HASH_ADAPT */ if (was_delete_marked - && !rec_get_deleted_flag( - rec, page_is_comp(buf_block_get_frame(block)))) { + && !rec_get_deleted_flag(rec, page_rec_is_comp(rec))) { /* The new updated record owns its possible externally stored fields */ @@ -3423,7 +3432,7 @@ btr_cur_update_in_place( if (page_zip && !(flags & BTR_KEEP_IBUF_BITMAP) && !dict_index_is_clust(index) - && page_is_leaf(buf_block_get_frame(block))) { + && page_rec_is_leaf(rec)) { /* Update the free bits in the insert buffer. */ ut_ad(!index->table->is_temporary()); ibuf_update_free_bits_zip(block, mtr); @@ -3480,15 +3489,16 @@ static void btr_cur_trim_alter_metadata(dtuple_t* entry, mtr.commit(); return; } - ut_ad(fil_page_get_type(block->page.frame) == FIL_PAGE_TYPE_BLOB); - ut_ad(mach_read_from_4(&block->page.frame + page_t* page = block->page.frame; + ut_ad(fil_page_get_type(page) == FIL_PAGE_TYPE_BLOB); + ut_ad(mach_read_from_4(&page [FIL_PAGE_DATA + BTR_BLOB_HDR_NEXT_PAGE_NO]) == FIL_NULL); - ut_ad(mach_read_from_4(&block->page.frame + ut_ad(mach_read_from_4(&page [FIL_PAGE_DATA + BTR_BLOB_HDR_PART_LEN]) == mach_read_from_4(ptr + BTR_EXTERN_LEN + 4)); n_fields = mach_read_from_4( - &block->page.frame[FIL_PAGE_DATA + BTR_BLOB_HDR_SIZE]) + &page[FIL_PAGE_DATA + BTR_BLOB_HDR_SIZE]) + index->first_user_field(); /* Rollback should not increase the number of fields. */ ut_ad(n_fields <= index->n_fields); @@ -3610,7 +3620,7 @@ btr_cur_optimistic_update( ulint i; block = btr_cur_get_block(cursor); - page = buf_block_get_frame(block); + page = btr_cur_get_page(cursor); rec = btr_cur_get_rec(cursor); index = cursor->index(); ut_ad(index->has_locking()); @@ -3883,11 +3893,9 @@ btr_cur_pess_upd_restore_supremum( const rec_t* rec, /*!< in: updated record */ mtr_t* mtr) /*!< in: mtr */ { - page_t* page; + const page_t* const page = block->page.frame; - page = buf_block_get_frame(block); - - if (page_rec_get_next(page_get_infimum_rec(page)) != rec) { + if (!page_rec_is_first(page, rec)) { /* Updated record is not the first user record on its page */ return DB_SUCCESS; } @@ -3901,12 +3909,14 @@ btr_cur_pess_upd_restore_supremum( if (UNIV_UNLIKELY(!prev_block)) { return DB_CORRUPTION; } - ut_ad(!memcmp_aligned<4>(prev_block->page.frame + FIL_PAGE_NEXT, - block->page.frame + FIL_PAGE_OFFSET, 4)); + + ut_d(const page_t* prev_page = prev_block->page.frame); + ut_ad(!memcmp_aligned<4>(prev_page + FIL_PAGE_NEXT, + page + FIL_PAGE_OFFSET, 4)); lock_rec_reset_and_inherit_gap_locks(*prev_block, block_id, PAGE_HEAP_NO_SUPREMUM, - page_rec_get_heap_no(rec)); + page_rec_get_heap_no(page, rec)); return DB_SUCCESS; } @@ -3990,6 +4000,8 @@ btr_cur_pessimistic_update( cursor, offsets, offsets_heap, update, cmpl_info, thr, trx_id, mtr); + rec = btr_cur_get_rec(cursor); + switch (err) { case DB_ZIP_OVERFLOW: case DB_UNDERFLOW: @@ -4016,7 +4028,6 @@ btr_cur_pessimistic_update( return(err); } - rec = btr_cur_get_rec(cursor); ut_ad(rec_offs_validate(rec, index, *offsets)); dtuple_t* new_entry; @@ -4051,7 +4062,7 @@ btr_cur_pessimistic_update( /* We have to set appropriate extern storage bits in the new record to be inserted: we have to remember which fields were such */ - ut_ad(!page_is_comp(block->page.frame) || !rec_get_node_ptr_flag(rec)); + ut_ad(!page_rec_is_comp(rec) || !rec_get_node_ptr_flag(rec)); ut_ad(rec_offs_validate(rec, index, *offsets)); if ((flags & BTR_NO_UNDO_LOG_FLAG) @@ -4101,7 +4112,7 @@ btr_cur_pessimistic_update( goto err_exit; } - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_rec_is_leaf(rec)); ut_ad(dict_index_is_clust(index)); if (UNIV_UNLIKELY(!(flags & BTR_KEEP_POS_FLAG))) { ut_ad(page_zip != NULL); @@ -4223,7 +4234,7 @@ btr_cur_pessimistic_update( } bool adjust = big_rec_vec && (flags & BTR_KEEP_POS_FLAG); - ut_ad(!adjust || page_is_leaf(block->page.frame)); + ut_ad(!adjust || page_rec_is_leaf(rec)); if (btr_cur_compress_if_useful(cursor, adjust, mtr)) { if (adjust) { @@ -4231,7 +4242,7 @@ btr_cur_pessimistic_update( true, *offsets); } } else if (!dict_index_is_clust(index) - && page_is_leaf(block->page.frame)) { + && page_rec_is_leaf(rec)) { /* Update the free bits in the insert buffer. This is the same block which was skipped by BTR_KEEP_IBUF_BITMAP. */ @@ -4246,7 +4257,7 @@ btr_cur_pessimistic_update( #if 0 // FIXME: this used to be a no-op, and will cause trouble if enabled if (!big_rec_vec - && page_is_leaf(block->page.frame) + && page_rec_is_leaf(rec) && !dict_index_is_online_ddl(index)) { mtr->release(index->lock); /* NOTE: We cannot release root block latch here, because it @@ -4269,13 +4280,13 @@ btr_cur_pessimistic_update( BTR_KEEP_IBUF_BITMAP. */ if (!dict_index_is_clust(index) && !index->table->is_temporary() - && page_is_leaf(block->page.frame)) { + && page_is_leaf(btr_cur_get_page(cursor))) { ibuf_reset_free_bits(block); } } if (big_rec_vec != NULL) { - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_is_leaf(btr_cur_get_page(cursor))); ut_ad(dict_index_is_clust(index)); ut_ad(flags & BTR_KEEP_POS_FLAG); @@ -4331,7 +4342,8 @@ btr_cur_pessimistic_update( stored fields */ #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip - || page_zip_validate(page_zip, block->page.frame, index)); + || page_zip_validate(btr_cur_get_page_zip(cursor), + btr_cur_get_page(cursor), index)); #endif /* UNIV_ZIP_DEBUG */ btr_cur_unmark_extern_fields(btr_cur_get_block(cursor), rec, index, *offsets, mtr); @@ -4442,7 +4454,7 @@ btr_cur_del_mark_set_clust_rec( ut_ad(dict_index_is_clust(index)); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); - ut_ad(buf_block_get_frame(block) == page_align(rec)); + ut_ad(block->page.frame == page_align(rec)); ut_ad(page_rec_is_leaf(rec)); ut_ad(mtr->is_named_space(index->table->space)); @@ -4539,8 +4551,8 @@ btr_cur_optimistic_delete( index, the mtr must be committed before latching any further pages */ { - buf_block_t* block; - rec_t* rec; + buf_block_t* block = btr_cur_get_block(cursor); + rec_t* rec = btr_cur_get_rec(cursor); mem_heap_t* heap = NULL; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; @@ -4554,20 +4566,18 @@ btr_cur_optimistic_delete( /* This is intended only for leaf page deletions */ - block = btr_cur_get_block(cursor); - ut_ad(block->page.id().space() == cursor->index()->table->space->id); - ut_ad(page_is_leaf(buf_block_get_frame(block))); + ut_ad(page_rec_is_leaf(rec)); ut_ad(!dict_index_is_online_ddl(cursor->index()) || cursor->index()->is_clust() || (flags & BTR_CREATE_FLAG)); - rec = btr_cur_get_rec(cursor); - offsets = rec_get_offsets(rec, cursor->index(), offsets, cursor->index()->n_core_fields, ULINT_UNDEFINED, &heap); + page_t* page = cursor->block()->page.frame; + dberr_t err = DB_SUCCESS; if (rec_offs_any_extern(offsets) || !btr_cur_can_delete_without_compress(cursor, @@ -4581,7 +4591,7 @@ btr_cur_optimistic_delete( } if (UNIV_UNLIKELY(block->page.id().page_no() == cursor->index()->page - && page_get_n_recs(block->page.frame) == 1 + && page_get_n_recs(page) == 1 + (cursor->index()->is_instant() && !rec_is_metadata(rec, *cursor->index())) && !cursor->index() @@ -4593,8 +4603,7 @@ btr_cur_optimistic_delete( If we are deleting the metadata record and the table becomes empty, clean up the whole page. */ dict_index_t* index = cursor->index(); - const rec_t* first_rec = page_rec_get_next_const( - page_get_infimum_rec(block->page.frame)); + const rec_t* first_rec = page_rec_get_first(page); if (UNIV_UNLIKELY(!first_rec)) { err = DB_CORRUPTION; goto func_exit; @@ -4628,10 +4637,9 @@ btr_cur_optimistic_delete( } { - page_t* page = buf_block_get_frame(block); page_zip_des_t* page_zip= buf_block_get_page_zip(block); - if (UNIV_UNLIKELY(rec_get_info_bits(rec, page_rec_is_comp(rec)) + if (UNIV_UNLIKELY(rec_get_info_bits(rec, page_is_comp(page)) & REC_INFO_MIN_REC_FLAG)) { /* This should be rolling back instant ADD COLUMN. If this is a recovered transaction, then @@ -4744,7 +4752,7 @@ btr_cur_pessimistic_delete( #endif /* UNIV_DEBUG */ block = btr_cur_get_block(cursor); - page = buf_block_get_frame(block); + page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); ut_ad(flags == 0 || flags == BTR_CREATE_FLAG); @@ -4828,8 +4836,7 @@ btr_cur_pessimistic_delete( (in the rollback of instant ALTER TABLE) and the table becomes empty, clean up the whole page. */ - const rec_t* first_rec = page_rec_get_next_const( - page_get_infimum_rec(page)); + const rec_t* first_rec = page_rec_get_first(page); if (UNIV_UNLIKELY(!first_rec)) { *err = DB_CORRUPTION; goto err_exit; @@ -4867,8 +4874,8 @@ btr_cur_pessimistic_delete( ut_ad(!ret); goto err_exit; } - } else if (UNIV_UNLIKELY(page_rec_is_first(rec, page))) { - if (page_rec_is_last(rec, page)) { + } else if (UNIV_UNLIKELY(page_rec_is_first(page, rec))) { + if (page_rec_is_last(page, rec)) { discard_page: ut_ad(page_get_n_recs(page) == 1); /* If there is only one record, drop @@ -4880,7 +4887,8 @@ btr_cur_pessimistic_delete( goto return_after_reservations; } - if (UNIV_UNLIKELY(!(next_rec = page_rec_get_next(rec)))) { + next_rec = page_rec_get_next(page, rec); + if (UNIV_UNLIKELY(!next_rec)) { ut_ad(!ret); *err = DB_CORRUPTION; goto err_exit; @@ -5054,8 +5062,6 @@ class btr_est_cur_t m_block->page.id at the moment when the child's page id is already found, but the child's block has not fetched yet */ page_id_t m_page_id; - /** Current block */ - buf_block_t *m_block; /** Page search mode, can differ from m_mode for non-leaf pages, see c-tor comments for details */ page_cur_mode_t m_page_mode; @@ -5071,13 +5077,13 @@ class btr_est_cur_t btr_est_cur_t(dict_index_t *index, const dtuple_t &tuple, page_cur_mode_t mode) : m_tuple(tuple), m_mode(mode), - m_page_id(index->table->space_id, index->page), m_block(nullptr) + m_page_id(index->table->space_id, index->page) { - ut_ad(dict_index_check_search_tuple(index, &tuple)); ut_ad(dtuple_check_typed(&tuple)); m_page_cur.index = index; + m_page_cur.block = nullptr; /* We use these modified search modes on non-leaf levels of the B-tree. These let us end up in the right B-tree leaf. In that leaf we use the original search mode. */ @@ -5113,11 +5119,11 @@ class btr_est_cur_t @return true on success or false otherwise. */ bool fetch_child(ulint level, mtr_t &mtr, const buf_block_t *right_parent) { - buf_block_t *parent_block= m_block; + buf_block_t *parent_block= block(); - m_block= btr_block_get(*index(), m_page_id.page_no(), RW_S_LATCH, !level, - &mtr, nullptr); - if (!m_block) + m_page_cur.block= + btr_block_get(*index(), m_page_id.page_no(), RW_S_LATCH, !level, &mtr); + if (!m_page_cur.block) return false; if (parent_block && parent_block != right_parent) @@ -5126,8 +5132,10 @@ class btr_est_cur_t mtr.rollback_to_savepoint(1, 2); } + m_page_cur.rec= m_page_cur.block->page.frame; + return level == ULINT_UNDEFINED || - btr_page_get_level(m_block->page.frame) == level; + btr_page_get_level(m_page_cur.rec) == level; } /** Sets page mode for leaves */ @@ -5141,24 +5149,26 @@ class btr_est_cur_t @return true on success, false otherwise. */ bool search_on_page(ulint level, ulint root_height, bool left) { - if (level != btr_page_get_level(m_block->page.frame)) + page_t *const p= page(); + + if (level != btr_page_get_level(p)) return false; - m_n_recs= page_get_n_recs(m_block->page.frame); + m_n_recs= page_get_n_recs(p); if (dtuple_get_n_fields(&m_tuple) > 0) { m_up_bytes= m_low_bytes= 0; - m_page_cur.block= m_block; if (page_cur_search_with_match(&m_tuple, m_page_mode, &m_up_match, &m_low_match, &m_page_cur, nullptr)) return false; - m_nth_rec= page_rec_get_n_recs_before(page_cur_get_rec(&m_page_cur)); + m_nth_rec= page_rec_get_n_recs_before(page_cur_get_page(&m_page_cur), + page_cur_get_rec(&m_page_cur)); } else if (left) { - page_cur_set_before_first(m_block, &m_page_cur); + m_page_cur.rec = page_get_infimum_rec(p); if (level) { if (!page_cur_move_to_next(&m_page_cur)) @@ -5173,14 +5183,11 @@ class btr_est_cur_t m_nth_rec= m_n_recs; if (!level) { - page_cur_set_after_last(m_block, &m_page_cur); + m_page_cur.rec= page_get_supremum_rec(p); ++m_nth_rec; } else - { - m_page_cur.block= m_block; - m_page_cur.rec= page_rec_get_nth(m_block->page.frame, m_nth_rec); - } + m_page_cur.rec= page_rec_get_nth(p, m_nth_rec); } return true; @@ -5204,13 +5211,8 @@ class btr_est_cur_t /** @return true if left border should be counted */ bool should_count_the_left_border() const { - if (dtuple_get_n_fields(&m_tuple) > 0) - { - ut_ad(!page_rec_is_infimum(page_cur_get_rec(&m_page_cur))); - return !page_rec_is_supremum(page_cur_get_rec(&m_page_cur)); - } - ut_ad(page_rec_is_infimum(page_cur_get_rec(&m_page_cur))); - return false; + ut_ad(page_cur_is_before_first(&m_page_cur) == (m_tuple.n_fields == 0)); + return m_tuple.n_fields && !page_cur_is_after_last(&m_page_cur); } /** @return true if right border should be counted */ @@ -5218,8 +5220,7 @@ class btr_est_cur_t { if (dtuple_get_n_fields(&m_tuple) > 0) { - const rec_t *rec= page_cur_get_rec(&m_page_cur); - ut_ad(!(m_mode == PAGE_CUR_L && page_rec_is_supremum(rec))); + ut_ad(m_mode != PAGE_CUR_L || !page_cur_is_after_last(&m_page_cur)); return (m_mode == PAGE_CUR_LE /* if the range is '<=' */ /* and the record was found */ @@ -5230,7 +5231,7 @@ class btr_est_cur_t cursor will be positioned at 5 and we should count the border, but if x < 2 is specified, then the cursor will be positioned at 'inf' and we should not count the border */ - && !page_rec_is_infimum(rec)); + && !page_cur_is_before_first(&m_page_cur)); /* Notice that for "WHERE col <= 'foo'" the server passes to ha_innobase::records_in_range(): min_key=NULL (left-unbounded) which is expected max_key='foo' flag=HA_READ_AFTER_KEY (PAGE_CUR_G), which is @@ -5239,7 +5240,7 @@ class btr_est_cur_t of the requested one (can also be positioned on the 'sup') and we should not count the right border. */ } - ut_ad(page_rec_is_supremum(page_cur_get_rec(&m_page_cur))); + ut_ad(page_cur_is_after_last(&m_page_cur)); /* The range specified is without a right border, just 'x > 123' or 'x >= 123' and search_on_page() positioned the cursor on the @@ -5251,15 +5252,18 @@ class btr_est_cur_t const dict_index_t *index() const { return m_page_cur.index; } /** @return current block */ - const buf_block_t *block() const { return m_block; } + buf_block_t *block() const { return m_page_cur.block; } + + /** @return current page frame */ + page_t *page() const { return block()->page.frame; } /** @return current page id */ page_id_t page_id() const { return m_page_id; } - /** Copies block pointer and savepoint from another btr_est_cur_t in the case + /** Copies the cursor from another btr_est_cur_t in the case if both left and right border cursors point to the same block. @param o reference to the other btr_est_cur_t object. */ - void set_block(const btr_est_cur_t &o) { m_block= o.m_block; } + void set_block(const btr_est_cur_t &o) { m_page_cur= o.m_page_cur; } /** @return current record number. */ ulint nth_rec() const { return m_nth_rec; } @@ -5317,15 +5321,14 @@ static ha_rows btr_estimate_n_rows_in_range_on_level( pages */ const fil_space_t *space= index->table->space; - page_id_t page_id(space->id, - btr_page_get_next(buf_block_get_frame(left_cur.block()))); + page_id_t page_id(space->id, btr_page_get_next(left_cur.page())); if (page_id.page_no() == FIL_NULL) goto inexact; do { - page_t *page; + const page_t *page; buf_block_t *prev_block= block; /* Fetch the page. */ @@ -5341,10 +5344,13 @@ static ha_rows btr_estimate_n_rows_in_range_on_level( mtr.rollback_to_savepoint(savepoint - 2, savepoint - 1); } - if (!block || btr_page_get_level(buf_block_get_frame(block)) != level) + if (!block) goto inexact; - page= buf_block_get_frame(block); + page= block->page.frame; + + if (btr_page_get_level(page) != level) + goto inexact; /* It is possible but highly unlikely that the page was originally written by an old version of InnoDB that did not initialize FIL_PAGE_TYPE on other @@ -5466,7 +5472,7 @@ ha_rows btr_estimate_n_rows_in_range(dict_index_t *index, if (height == ULINT_UNDEFINED) { /* We are in the root node */ - height= btr_page_get_level(buf_block_get_frame(p1.block())); + height= btr_page_get_level(p1.page()); root_height= height; } @@ -5937,7 +5943,7 @@ struct btr_blob_log_check_t { uint32_t page_no = FIL_NULL; if (UNIV_UNLIKELY(m_op == BTR_STORE_INSERT_BULK)) { - offs = page_offset(*m_rec); + offs = *m_rec - (*m_block)->page.frame; page_no = (*m_block)->page.id().page_no(); (*m_block)->page.fix(); ut_ad(page_no != FIL_NULL); @@ -5969,7 +5975,7 @@ struct btr_blob_log_check_t { we are holding a buffer-fix on it. */ m_pcur->btr_cur.page_cur.block->page.unfix(); m_pcur->btr_cur.page_cur.rec - = m_pcur->btr_cur.page_cur.block->page.frame + = btr_pcur_get_page(m_pcur) + offs; } else { ut_ad(m_pcur->rel_pos == BTR_PCUR_ON); @@ -6043,10 +6049,10 @@ btr_store_big_rec_extern_fields( || btr_mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK)); ut_ad(btr_mtr->memo_contains_flagged(rec_block, MTR_MEMO_PAGE_X_FIX)); - ut_ad(buf_block_get_frame(rec_block) == page_align(rec)); + ut_ad(rec_block->page.frame == page_align(rec)); ut_a(dict_index_is_clust(index)); - if (!fil_page_index_page_check(page_align(rec))) { + if (!fil_page_index_page_check(rec_block->page.frame)) { if (op != BTR_STORE_INSERT_BULK) { return DB_PAGE_CORRUPTED; } @@ -6185,46 +6191,44 @@ btr_store_big_rec_extern_fields( rec_block->zip_size(), RW_X_LATCH, nullptr, BUF_GET, &mtr, &error)) { + page_t* prev = prev_block->page.frame; + if (page_zip) { mtr.write<4>(*prev_block, - prev_block->page.frame - + FIL_PAGE_NEXT, + prev + FIL_PAGE_NEXT, page_no); memcpy_aligned<4>( buf_block_get_page_zip( prev_block) ->data + FIL_PAGE_NEXT, - prev_block->page.frame - + FIL_PAGE_NEXT, 4); + prev + FIL_PAGE_NEXT, 4); } else { mtr.write<4>(*prev_block, BTR_BLOB_HDR_NEXT_PAGE_NO - + FIL_PAGE_DATA - + prev_block->page.frame, + + FIL_PAGE_DATA + prev, page_no); } } else { goto alloc_fail; } - ut_ad(!page_has_siblings(block->page.frame)); - ut_ad(!fil_page_get_type(block->page.frame)); + page_t* page = block->page.frame; - if (page_zip) { + ut_ad(!page_has_siblings(page)); + ut_ad(!fil_page_get_type(page)); + + if (UNIV_LIKELY_NULL(page_zip)) { int err; page_zip_des_t* blob_page_zip; - mtr.write<1>(*block, - FIL_PAGE_TYPE + 1 - + block->page.frame, + mtr.write<1>(*block, FIL_PAGE_TYPE + 1 + page, prev_page_no == FIL_NULL ? FIL_PAGE_TYPE_ZBLOB : FIL_PAGE_TYPE_ZBLOB2); block->page.zip.data[FIL_PAGE_TYPE + 1] - = block->page.frame[FIL_PAGE_TYPE + 1]; + = page[FIL_PAGE_TYPE + 1]; - c_stream.next_out = block->page.frame - + FIL_PAGE_DATA; + c_stream.next_out = page + FIL_PAGE_DATA; c_stream.avail_out = static_cast( payload_size_zip); @@ -6233,8 +6237,7 @@ btr_store_big_rec_extern_fields( ut_a(err == Z_STREAM_END || c_stream.avail_out == 0); - mtr.memcpy(*block, - FIL_PAGE_DATA, + mtr.memcpy(*block, FIL_PAGE_DATA + page, page_zip_get_size(page_zip) - FIL_PAGE_DATA - c_stream.avail_out); @@ -6245,7 +6248,7 @@ btr_store_big_rec_extern_fields( ut_ad(blob_page_zip); ut_ad(page_zip_get_size(blob_page_zip) == page_zip_get_size(page_zip)); - memcpy(blob_page_zip->data, block->page.frame, + memcpy(blob_page_zip->data, page, page_zip_get_size(page_zip)); if (err == Z_OK && prev_page_no != FIL_NULL) { @@ -6297,8 +6300,7 @@ btr_store_big_rec_extern_fields( break; } } else { - mtr.write<1>(*block, FIL_PAGE_TYPE + 1 - + block->page.frame, + mtr.write<1>(*block, FIL_PAGE_TYPE + 1 + page, FIL_PAGE_TYPE_BLOB); if (extern_len > payload_size) { @@ -6310,18 +6312,17 @@ btr_store_big_rec_extern_fields( mtr.memcpy( *block, FIL_PAGE_DATA + BTR_BLOB_HDR_SIZE - + block->page.frame, + + page, static_cast (big_rec_vec->fields[i].data) + big_rec_vec->fields[i].len - extern_len, store_len); mtr.write<4>(*block, BTR_BLOB_HDR_PART_LEN - + FIL_PAGE_DATA - + block->page.frame, + + FIL_PAGE_DATA + page, store_len); compile_time_assert(FIL_NULL == 0xffffffff); mtr.memset(block, BTR_BLOB_HDR_NEXT_PAGE_NO - + FIL_PAGE_DATA, 4, 0xff); + + FIL_PAGE_DATA + page, 4, 0xff); extern_len -= store_len; @@ -6396,21 +6397,18 @@ btr_store_big_rec_extern_fields( return(error); } -/** Check the FIL_PAGE_TYPE on an uncompressed BLOB page. +ATTRIBUTE_COLD +/** Report an invalid FIL_PAGE_TYPE on an uncompressed BLOB page. @param block uncompressed BLOB page +@param type invalid FIL_PAGE_TYPE @param op operation @return whether the type is invalid */ -static bool btr_check_blob_fil_page_type(const buf_block_t& block, - const char *op) +static bool btr_report_blob_fil_page_type(const buf_block_t& block, + uint16_t type, + const char *op) { - uint16_t type= fil_page_get_type(block.page.frame); - - if (UNIV_LIKELY(type == FIL_PAGE_TYPE_BLOB)); - else if (fil_space_t *space= fil_space_t::get(block.page.id().space())) + if (fil_space_t *space= fil_space_t::get(block.page.id().space())) { - /* Old versions of InnoDB did not initialize FIL_PAGE_TYPE on BLOB - pages. Do not print anything about the type mismatch when reading - a BLOB page that may be from old versions. */ bool fail= space->full_crc32() || DICT_TF_HAS_ATOMIC_BLOBS(space->flags); if (fail) sql_print_error("InnoDB: FIL_PAGE_TYPE=%u on BLOB %s file %s page %u", @@ -6419,9 +6417,27 @@ static bool btr_check_blob_fil_page_type(const buf_block_t& block, space->release(); return fail; } + + /* Old versions of InnoDB did not initialize FIL_PAGE_TYPE on BLOB pages. + Do not print anything about the type mismatch when reading a BLOB + page that may be from old versions. */ return false; } +/** Check the FIL_PAGE_TYPE on an uncompressed BLOB page. +@param block uncompressed BLOB page +@param page page frame +@param op operation +@return whether the type is invalid */ +static bool btr_check_blob_fil_page_type(const buf_block_t& block, + const page_t *page, + const char *op) +{ + uint16_t type= fil_page_get_type(page); + return UNIV_UNLIKELY(type != FIL_PAGE_TYPE_BLOB) && + btr_report_blob_fil_page_type(block, type, op); +} + /*******************************************************************//** Frees the space in an externally stored field to the file space management if the field in data is owned by the externally stored field, @@ -6531,7 +6547,7 @@ btr_free_externally_stored_field( ut_ad(!btr_search_check_marked_free_index(block)); #endif - const page_t* page = buf_block_get_frame(ext_block); + const page_t* page = ext_block->page.frame; if (ext_zip_size) { /* Note that page_zip will be NULL @@ -6567,7 +6583,8 @@ btr_free_externally_stored_field( } } else { ut_ad(!block->page.zip.data); - btr_check_blob_fil_page_type(*ext_block, "purge"); + btr_check_blob_fil_page_type(*ext_block, page, + "purge"); const uint32_t next_page_no = mach_read_from_4( page + FIL_PAGE_DATA @@ -6701,15 +6718,21 @@ btr_copy_blob_prefix( mtr_start(&mtr); block = buf_page_get(id, 0, RW_S_LATCH, &mtr); - if (!block || btr_check_blob_fil_page_type(*block, "read")) { + if (!block) { +invalid: mtr.commit(); return copied_len; } + if (!buf_page_make_young_if_needed(&block->page)) { buf_read_ahead_linear(id, 0, false); } - page = buf_block_get_frame(block); + page = block->page.frame; + + if (btr_check_blob_fil_page_type(*block, page, "read")) { + goto invalid; + } blob_header = page + offset; part_len = btr_blob_get_part_len(blob_header); diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 642db0e9f1c57..24d5592baa81b 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -248,7 +248,7 @@ btr_defragment_calc_n_recs_for_size( ulint* n_recs_size) /*!< out: actual size of the records that fit in size_limit. */ { - page_t* page = buf_block_get_frame(block); + page_t* page = block->page.frame; ulint n_recs = 0; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; @@ -260,7 +260,7 @@ btr_defragment_calc_n_recs_for_size( const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; page_cur_set_before_first(block, &cur); while (rec_t* cur_rec = page_cur_move_to_next(&cur)) { - if (page_rec_is_supremum(cur_rec)) { + if (page_rec_is_supremum(block->page.frame, cur_rec)) { break; } offsets = rec_get_offsets(cur_rec, index, offsets, n_core, @@ -306,7 +306,7 @@ btr_page_search_father_node_ptr( const auto level = btr_page_get_level(btr_cur_get_page(cursor)); const rec_t* user_rec = btr_cur_get_rec(cursor); - ut_a(page_rec_is_user_rec(user_rec)); + ut_a(page_rec_is_user_rec(btr_cur_get_page(cursor), user_rec)); if (btr_cur_search_to_nth_level(level + 1, dict_index_build_node_ptr(index, @@ -333,8 +333,7 @@ btr_page_search_father_node_ptr( static bool btr_page_search_father(mtr_t *mtr, btr_cur_t *cursor) { - rec_t *rec= - page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame)); + rec_t *rec= page_rec_get_first(cursor->block()->page.frame); if (UNIV_UNLIKELY(!rec)) return false; cursor->page_cur.rec= rec; @@ -363,8 +362,8 @@ btr_defragment_merge_pages( mem_heap_t* heap, /*!< in/out: pointer to memory heap */ mtr_t* mtr) /*!< in/out: mini-transaction */ { - page_t* from_page = buf_block_get_frame(from_block); - page_t* to_page = buf_block_get_frame(to_block); + page_t* from_page = from_block->page.frame; + page_t* to_page = to_block->page.frame; ulint level = btr_page_get_level(from_page); ulint n_recs = page_get_n_recs(from_page); ulint new_data_size = page_get_data_size(to_page); @@ -505,8 +504,7 @@ btr_defragment_merge_pages( != DB_SUCCESS) { return nullptr; } - rec = page_rec_get_next( - page_get_infimum_rec(from_page)); + rec = page_rec_get_first(from_page); if (!rec) { return nullptr; } @@ -574,13 +572,13 @@ btr_defragment_n_pages( n_pages = BTR_DEFRAGMENT_MAX_N_PAGES; } - first_page = buf_block_get_frame(block); + first_page = block->page.frame; const ulint zip_size = index->table->space->zip_size(); /* 1. Load the pages and calculate the total data size. */ blocks[0] = block; for (uint i = 1; i <= n_pages; i++) { - page_t* page = buf_block_get_frame(blocks[i-1]); + page_t* page = blocks[i - 1]->page.frame; uint32_t page_no = btr_page_get_next(page); total_data_size += page_get_data_size(page); total_n_recs += page_get_n_recs(page); @@ -774,10 +772,10 @@ static void btr_defragment_chunk(void*) /* If we haven't reached the end of the index, place the cursor on the last record of last page, store the cursor position, and put back in queue. */ - page_t* last_page = buf_block_get_frame(last_block); + page_t* last_page = last_block->page.frame; rec_t* rec = page_rec_get_prev( - page_get_supremum_rec(last_page)); - if (rec && page_rec_is_user_rec(rec)) { + last_page, page_get_supremum_rec(last_page)); + if (rec && page_rec_is_user_rec(last_page, rec)) { page_cur_position(rec, last_block, btr_pcur_get_page_cur( item->pcur)); diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index d30f037ab995f..886858319ab99 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -62,24 +62,16 @@ btr_pcur_store_position( btr_pcur_t* cursor, /*!< in: persistent cursor */ mtr_t* mtr) /*!< in: mtr */ { - page_cur_t* page_cursor; - buf_block_t* block; - rec_t* rec; - dict_index_t* index; - ulint offs; - ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - block = btr_pcur_get_block(cursor); - index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor)); - - page_cursor = btr_pcur_get_page_cur(cursor); + buf_block_t* block = btr_pcur_get_block(cursor); + const page_t* const page = btr_pcur_get_page(cursor); + dict_index_t* index = cursor->index(); - rec = page_cur_get_rec(page_cursor); - offs = rec - block->page.frame; - ut_ad(block->page.id().page_no() - == page_get_page_no(block->page.frame)); + const rec_t* rec = btr_pcur_get_rec(cursor); + const ulint offs = ulint(rec - page); + ut_ad(block->page.id().page_no() == page_get_page_no(page)); ut_ad(block->page.buf_fix_count()); /* For spatial index, when we do positioning on parent buffer if necessary, it might not hold latches, but the @@ -90,13 +82,13 @@ btr_pcur_store_position( && mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK))); - if (page_is_empty(block->page.frame)) { + if (page_is_empty(page)) { /* It must be an empty index tree; NOTE that in this case we do not store the modify_clock, but always do a search if we restore the cursor position */ - ut_a(!page_has_siblings(block->page.frame)); - ut_ad(page_is_leaf(block->page.frame)); + ut_a(!page_has_siblings(page)); + ut_ad(page_is_leaf(page)); ut_ad(block->page.id().page_no() == index->page); if (page_rec_is_supremum_low(offs)) { @@ -110,14 +102,14 @@ btr_pcur_store_position( } if (page_rec_is_supremum_low(offs)) { - rec = page_rec_get_prev(rec); - if (UNIV_UNLIKELY(!rec || page_rec_is_infimum(rec))) { + rec = page_rec_get_prev(page, rec); + if (UNIV_UNLIKELY(!rec || page_rec_is_infimum(page, rec))) { ut_ad("corrupted index" == 0); cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE; return; } - ut_ad(!page_rec_is_infimum(rec)); + ut_ad(!page_rec_is_infimum(page, rec)); if (UNIV_UNLIKELY(rec_is_metadata(rec, *index))) { #if 0 /* MDEV-22867 had to relax this */ /* If the table is emptied during an ALGORITHM=NOCOPY @@ -128,16 +120,16 @@ btr_pcur_store_position( #endif ut_ad(index->is_instant() || block->page.id().page_no() != index->page); - ut_ad(page_get_n_recs(block->page.frame) == 1); - ut_ad(page_is_leaf(block->page.frame)); - ut_ad(!page_has_prev(block->page.frame)); + ut_ad(page_get_n_recs(page) == 1); + ut_ad(page_is_leaf(page)); + ut_ad(!page_has_prev(page)); cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE; return; } cursor->rel_pos = BTR_PCUR_AFTER; } else if (page_rec_is_infimum_low(offs)) { - rec = page_rec_get_next(rec); + rec = page_rec_get_next(page, rec); if (UNIV_UNLIKELY(!rec)) { ut_ad("corrupted page" == 0); @@ -145,10 +137,10 @@ btr_pcur_store_position( } if (rec_is_metadata(rec, *index)) { - ut_ad(!page_has_prev(block->page.frame)); - rec = page_rec_get_next(rec); + ut_ad(!page_has_prev(page)); + rec = page_rec_get_next(page, rec); ut_ad(rec); - if (!rec || page_rec_is_supremum(rec)) { + if (!rec || page_rec_is_supremum(page, rec)) { goto before_first; } } @@ -164,7 +156,7 @@ btr_pcur_store_position( } else { cursor->old_n_fields = static_cast( dict_index_get_n_unique_in_tree(index)); - if (index->is_spatial() && !page_rec_is_leaf(rec)) { + if (index->is_spatial() && !page_is_leaf(page)) { ut_ad(dict_index_get_n_unique_in_tree_nonleaf(index) == DICT_INDEX_SPATIAL_NODEPTR_SIZE); /* For R-tree, we have to compare @@ -534,7 +526,7 @@ btr_pcur_move_to_next_page( return err; } - const page_t* next_page = buf_block_get_frame(next_block); + const page_t* next_page = next_block->page.frame; if (UNIV_UNLIKELY(memcmp_aligned<4>(next_page + FIL_PAGE_PREV, page + FIL_PAGE_OFFSET, 4))) { diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 5d99e24273b41..91f638f917bd8 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -403,10 +403,12 @@ bool btr_search_update_block_hash_info(btr_search_t* info, buf_block_t* block) { ut_ad(block->page.lock.have_x() || block->page.lock.have_s()); + ut_ad(info->magic_n == BTR_SEARCH_MAGIC_N); + + const page_t* const page = block->page.frame; + ut_ad(page); info->last_hash_succ = FALSE; - ut_ad(block->page.frame); - ut_ad(info->magic_n == BTR_SEARCH_MAGIC_N); if ((block->n_hash_helps > 0) && (info->n_hash_potential > 0) @@ -433,13 +435,12 @@ btr_search_update_block_hash_info(btr_search_t* info, buf_block_t* block) block->left_side = info->left_side; } - if ((block->n_hash_helps > page_get_n_recs(block->page.frame) + if ((block->n_hash_helps > page_get_n_recs(page) / BTR_SEARCH_PAGE_BUILD_LIMIT) && (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) { if ((!block->index) - || (block->n_hash_helps - > 2U * page_get_n_recs(block->page.frame)) + || (block->n_hash_helps > 2U * page_get_n_recs(page)) || (block->n_fields != block->curr_n_fields) || (block->n_bytes != block->curr_n_bytes) || (block->left_side != block->curr_left_side)) { @@ -721,7 +722,7 @@ btr_search_update_hash_ref( const rec_t* rec = btr_cur_get_rec(cursor); - if (!page_rec_is_user_rec(rec)) { + if (!page_rec_is_user_rec(btr_cur_get_page(cursor), rec)) { goto func_exit; } @@ -767,7 +768,6 @@ btr_search_check_guess( const dtuple_t* tuple, ulint mode) { - rec_t* rec; ulint n_unique; ulint match; int cmp; @@ -779,10 +779,11 @@ btr_search_check_guess( n_unique = dict_index_get_n_unique_in_tree(cursor->index()); - rec = btr_cur_get_rec(cursor); + rec_t* rec = btr_cur_get_rec(cursor); + page_t* page = btr_cur_get_page(cursor); - if (UNIV_UNLIKELY(!page_rec_is_user_rec(rec) - || !page_rec_is_leaf(rec))) { + if (UNIV_UNLIKELY(!page_rec_is_user_rec(page, rec) + || !page_is_leaf(page))) { ut_ad("corrupted index" == 0); return false; } else if (cursor->index()->table->not_redundant()) { @@ -840,15 +841,15 @@ btr_search_check_guess( match = 0; if ((mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)) { - const rec_t* prev_rec = page_rec_get_prev(rec); + const rec_t* prev_rec = page_rec_get_prev(page, rec); if (UNIV_UNLIKELY(!prev_rec)) { ut_ad("corrupted index" == 0); goto exit_func; } - if (page_rec_is_infimum(prev_rec)) { - success = !page_has_prev(page_align(prev_rec)); + if (page_rec_is_infimum(page, prev_rec)) { + success = !page_has_prev(page); goto exit_func; } @@ -874,17 +875,17 @@ btr_search_check_guess( success = cmp >= 0; } } else { - ut_ad(!page_rec_is_supremum(rec)); + ut_ad(!page_rec_is_supremum(page, rec)); - const rec_t* next_rec = page_rec_get_next(rec); + const rec_t* next_rec = page_rec_get_next(page, rec); if (UNIV_UNLIKELY(!next_rec)) { ut_ad("corrupted index" == 0); goto exit_func; } - if (page_rec_is_supremum(next_rec)) { - if (!page_has_next(page_align(next_rec))) { + if (page_rec_is_supremum(page, next_rec)) { + if (!page_has_next(page)) { cursor->up_match = 0; success = true; } @@ -1153,7 +1154,7 @@ btr_search_guess_on_hash( mtr->memo_push(block, mtr_memo_type_t(latch_mode)); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(block->page.frame, rec)); btr_cur_position(index, (rec_t*) rec, block, cursor); @@ -1212,14 +1213,16 @@ void btr_search_drop_page_hash_index(buf_block_t* block, || !(~buf_page_t::LRU_MASK & state) || block->page.lock.have_any()); ut_ad(state < buf_page_t::READ_FIX || state >= buf_page_t::WRITE_FIX); - ut_ad(page_is_leaf(block->page.frame)); + + const page_t* const page = block->page.frame; + + ut_ad(page_is_leaf(page)); /* We must not dereference block->index here, because it could be freed if (!index->table->get_ref_count() && !dict_sys.frozen()). Determine the ahi_slot based on the block contents. */ - const index_id_t index_id - = btr_page_get_index_id(block->page.frame); + const index_id_t index_id = btr_page_get_index_id(page); auto part = btr_search_sys.get_part(index_id, block->page.id().space()); @@ -1271,7 +1274,6 @@ void btr_search_drop_page_hash_index(buf_block_t* block, ut_a(n_fields > 0 || n_bytes > 0); - const page_t* const page = block->page.frame; ulint n_recs = page_get_n_recs(page); if (!n_recs) { ut_ad("corrupted adaptive hash index" == 0); @@ -1282,14 +1284,14 @@ void btr_search_drop_page_hash_index(buf_block_t* block, from the hash index */ rec = page_get_infimum_rec(page); - rec = page_rec_get_next_low(rec, page_is_comp(page)); + rec = page_rec_get_next(page, rec); ulint* folds; ulint n_cached = 0; ulint prev_fold = 0; if (rec && rec_is_metadata(rec, *index)) { - rec = page_rec_get_next_low(rec, page_is_comp(page)); + rec = page_rec_get_next(page, rec); if (!--n_recs) { /* The page only contains the hidden metadata record for instant ALTER TABLE that the adaptive hash index @@ -1305,10 +1307,10 @@ void btr_search_drop_page_hash_index(buf_block_t* block, while (rec) { if (n_cached >= n_recs) { - ut_ad(page_rec_is_supremum(rec)); + ut_ad(page_rec_is_supremum(page, rec)); break; } - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); offsets = rec_get_offsets( rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), @@ -1326,8 +1328,8 @@ void btr_search_drop_page_hash_index(buf_block_t* block, folds[n_cached++] = fold; next_rec: - rec = page_rec_get_next_low(rec, page_rec_is_comp(rec)); - if (!rec || page_rec_is_supremum(rec)) { + rec = page_rec_get_next(page, rec); + if (!rec || page_rec_is_supremum(page, rec)) { break; } prev_fold = fold; @@ -1461,11 +1463,13 @@ btr_search_build_page_hash_index( ut_ad(index); ut_ad(block->page.id().space() == index->table->space_id); ut_ad(!dict_index_is_ibuf(index)); - ut_ad(page_is_leaf(block->page.frame)); ut_ad(block->page.lock.have_x() || block->page.lock.have_s()); ut_ad(block->page.id().page_no() >= 3); + const page_t* const page = block->page.frame; + ut_ad(page_is_leaf(page)); + ahi_latch->rd_lock(SRW_LOCK_CALL); const bool enabled = btr_search_enabled; @@ -1496,7 +1500,6 @@ btr_search_build_page_hash_index( return; } - page_t* page = buf_block_get_frame(block); n_recs = page_get_n_recs(page); if (n_recs == 0) { @@ -1504,11 +1507,11 @@ btr_search_build_page_hash_index( return; } - rec = page_rec_get_next_const(page_get_infimum_rec(page)); + rec = page_rec_get_first(page); if (!rec) return; if (rec_is_metadata(rec, *index)) { - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); if (!rec || !--n_recs) return; } @@ -1527,7 +1530,7 @@ btr_search_build_page_hash_index( rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); - ut_ad(page_rec_is_supremum(rec) + ut_ad(page_rec_is_supremum(page, rec) || n_fields == rec_offs_n_fields(offsets) - (n_bytes > 0)); fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); @@ -1539,8 +1542,8 @@ btr_search_build_page_hash_index( n_cached++; } - while (const rec_t* next_rec = page_rec_get_next_const(rec)) { - if (page_rec_is_supremum(next_rec)) { + while (const rec_t* next_rec = page_rec_get_next(page, rec)) { + if (page_rec_is_supremum(page, next_rec)) { if (!left_side) { @@ -1827,24 +1830,18 @@ void btr_search_update_hash_on_delete(btr_cur_t *cursor) void btr_search_update_hash_node_on_insert(btr_cur_t *cursor, srw_spin_lock *ahi_latch) { - buf_block_t* block; - dict_index_t* index; - rec_t* rec; - ut_ad(ahi_latch == &btr_search_sys.get_part(*cursor->index())->latch); if (!btr_search_enabled) { return; } - rec = btr_cur_get_rec(cursor); - - block = btr_cur_get_block(cursor); + const rec_t* rec = btr_cur_get_rec(cursor); + buf_block_t *block = btr_cur_get_block(cursor); + dict_index_t* index = block->index; ut_ad(block->page.lock.have_x()); - index = block->index; - if (!index) { return; @@ -1873,7 +1870,8 @@ void btr_search_update_hash_node_on_insert(btr_cur_t *cursor, && (cursor->n_fields == block->curr_n_fields) && (cursor->n_bytes == block->curr_n_bytes) && !block->curr_left_side) { - if (const rec_t *new_rec = page_rec_get_next_const(rec)) { + if (const rec_t *new_rec = + page_rec_get_next(block->page.frame, rec)) { if (ha_search_and_update_if_found( &btr_search_sys.get_part(*cursor->index()) ->table, @@ -1957,10 +1955,11 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor, n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; const bool left_side = block->curr_left_side; + const page_t* page = block->page.frame; - ins_rec = page_rec_get_next_const(rec); + ins_rec = page_rec_get_next(page, rec); if (UNIV_UNLIKELY(!ins_rec)) goto drop; - next_rec = page_rec_get_next_const(ins_rec); + next_rec = page_rec_get_next(page, ins_rec); if (UNIV_UNLIKELY(!next_rec)) goto drop; offsets = rec_get_offsets(ins_rec, index, offsets, @@ -1968,7 +1967,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor, ULINT_UNDEFINED, &heap); ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index->id); - if (!page_rec_is_supremum(next_rec)) { + if (!page_rec_is_supremum(page, next_rec)) { offsets = rec_get_offsets( next_rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); @@ -1980,7 +1979,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor, btr_search_sys_t::partition* part= nullptr; bool locked = false; - if (!page_rec_is_infimum(rec) && !rec_is_metadata(rec, *index)) { + if (!page_rec_is_infimum(page, rec) && !rec_is_metadata(rec, *index)) { offsets = rec_get_offsets( rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); @@ -2027,7 +2026,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor, } check_next_rec: - if (page_rec_is_supremum(next_rec)) { + if (page_rec_is_supremum(page, next_rec)) { if (!left_side) { if (!locked) { diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 8fa8b92470b69..652163ced4055 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1201,11 +1201,11 @@ inline bool buf_pool_t::realloc(buf_block_t *block) hash_lock.lock(); if (block->page.can_relocate()) { + page_t* page = block->page.frame; + page_t* frame = new_block->page.frame; memcpy_aligned( - new_block->page.frame, block->page.frame, - srv_page_size); + frame, page, srv_page_size); mysql_mutex_lock(&buf_pool.flush_list_mutex); - const auto frame = new_block->page.frame; new_block->page.lock.free(); new (&new_block->page) buf_page_t(block->page); new_block->page.frame = frame; @@ -1252,13 +1252,12 @@ inline bool buf_pool_t::realloc(buf_block_t *block) &new_block->page); buf_block_modify_clock_inc(block); static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment"); - memset_aligned<4>(block->page.frame - + FIL_PAGE_OFFSET, 0xff, 4); + memset_aligned<4>(page + FIL_PAGE_OFFSET, 0xff, 4); static_assert(FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID % 4 == 2, "not perfect alignment"); - memset_aligned<2>(block->page.frame + memset_aligned<2>(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4); - MEM_UNDEFINED(block->page.frame, srv_page_size); + MEM_UNDEFINED(page, srv_page_size); block->page.set_state(buf_page_t::REMOVE_HASH); if (!fsp_is_system_temporary(id.space())) { buf_flush_relocate_on_flush_list(&block->page, @@ -2343,6 +2342,7 @@ buf_zip_decompress( ut_ad(block->zip_size()); ut_a(block->page.id().space() != 0); + page_t* page = block->page.frame; if (UNIV_UNLIKELY(check && !page_zip_verify_checksum(frame, size))) { @@ -2360,8 +2360,7 @@ buf_zip_decompress( switch (fil_page_get_type(frame)) { case FIL_PAGE_INDEX: case FIL_PAGE_RTREE: - if (page_zip_decompress(&block->page.zip, - block->page.frame, TRUE)) { + if (page_zip_decompress(&block->page.zip, page, TRUE)) { func_exit: if (space) { space->release(); @@ -2381,7 +2380,7 @@ buf_zip_decompress( case FIL_PAGE_TYPE_ZBLOB: case FIL_PAGE_TYPE_ZBLOB2: /* Copy to uncompressed storage. */ - memcpy(block->page.frame, frame, block->zip_size()); + memcpy(page, frame, block->zip_size()); goto func_exit; } @@ -2826,7 +2825,8 @@ buf_page_get_low( #ifdef UNIV_DEBUG if (!(++buf_dbg_counter % 5771)) buf_pool.validate(); #endif /* UNIV_DEBUG */ - ut_ad(block->page.frame); + page_t* page = block->page.frame; + ut_ad(page); /* The state = block->page.state() may be stale at this point, and in fact, at any point of time if we consider its @@ -2839,8 +2839,8 @@ buf_page_get_low( if (state >= buf_page_t::UNFIXED && allow_ibuf_merge - && fil_page_get_type(block->page.frame) == FIL_PAGE_INDEX - && page_is_leaf(block->page.frame)) { + && fil_page_get_type(page) == FIL_PAGE_INDEX + && page_is_leaf(page)) { block->page.lock.x_lock(); state = block->page.state(); ut_ad(state < buf_page_t::READ_FIX); @@ -2979,39 +2979,41 @@ buf_page_get_gen( mysql_mutex_unlock(&buf_pool.mutex); goto corrupted; } - else if (must_merge && - fil_page_get_type(block->page.frame) == FIL_PAGE_INDEX && - page_is_leaf(block->page.frame)) + else if (must_merge) { - block->page.lock.x_lock(); - s= block->page.state(); - ut_ad(s > buf_page_t::FREED); - ut_ad(s < buf_page_t::READ_FIX); - if (s < buf_page_t::UNFIXED) - { - block->page.lock.x_unlock(); - goto got_freed_page; - } - else + const page_t *const page= block->page.frame; + if (page_is_leaf(page) && fil_page_get_type(page) == FIL_PAGE_INDEX) { - if (block->page.is_ibuf_exist()) - block->page.clear_ibuf_exist(); - if (dberr_t e= - ibuf_merge_or_delete_for_page(block, page_id, block->zip_size())) + block->page.lock.x_lock(); + s= block->page.state(); + ut_ad(s > buf_page_t::FREED); + ut_ad(s < buf_page_t::READ_FIX); + if (s < buf_page_t::UNFIXED) { - if (err) - *err= e; - buf_pool.corrupted_evict(&block->page, s); - return nullptr; + block->page.lock.x_unlock(); + goto got_freed_page; + } + else + { + if (block->page.is_ibuf_exist()) + block->page.clear_ibuf_exist(); + if (dberr_t e= + ibuf_merge_or_delete_for_page(block, page_id, block->zip_size())) + { + if (err) + *err= e; + buf_pool.corrupted_evict(&block->page, s); + return nullptr; + } } - } - if (rw_latch == RW_X_LATCH) - { - mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); - return block; + if (rw_latch == RW_X_LATCH) + { + mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); + return block; + } + block->page.lock.x_unlock(); } - block->page.lock.x_unlock(); } mtr->page_lock(block, rw_latch); return block; @@ -3317,9 +3319,10 @@ static buf_block_t *buf_page_create_low(page_id_t page_id, ulint zip_size, !recv_recovery_is_on()) ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size); + page_t *const page= bpage->frame; static_assert(FIL_PAGE_PREV + 4 == FIL_PAGE_NEXT, "adjacent"); - memset_aligned<8>(bpage->frame + FIL_PAGE_PREV, 0xff, 8); - mach_write_to_2(bpage->frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED); + memset_aligned<8>(page + FIL_PAGE_PREV, 0xff, 8); + mach_write_to_2(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED); /* FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION is only used on the following pages: @@ -3327,8 +3330,8 @@ static buf_block_t *buf_page_create_low(page_id_t page_id, ulint zip_size, (2) FIL_RTREE_SPLIT_SEQ_NUM on R-tree pages (3) key_version on encrypted pages (not page 0:0) */ - memset(bpage->frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); - memset_aligned<8>(bpage->frame + FIL_PAGE_LSN, 0, 8); + memset(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); + memset_aligned<8>(page + FIL_PAGE_LSN, 0, 8); #ifdef UNIV_DEBUG if (!(++buf_dbg_counter % 5771)) buf_pool.validate(); @@ -3556,7 +3559,8 @@ dberr_t buf_page_t::read_complete(const fil_node_t &node) ut_ad(zip_size() == node.space->zip_size()); ut_ad(!!zip.ssize == !!zip.data); - const byte *read_frame= zip.data ? zip.data : frame; + page_t *page= frame; + const byte *read_frame= zip.data ? zip.data : page; ut_ad(read_frame); dberr_t err; @@ -3566,7 +3570,7 @@ dberr_t buf_page_t::read_complete(const fil_node_t &node) goto database_corrupted; } - if (belongs_to_unzip_LRU()) + if (zip.data && page) { buf_pool.n_pend_unzip++; auto ok= buf_zip_decompress(reinterpret_cast(this), false); @@ -3618,8 +3622,9 @@ dberr_t buf_page_t::read_complete(const fil_node_t &node) if (UNIV_UNLIKELY(err != DB_SUCCESS)) { database_corrupted: - if (belongs_to_unzip_LRU()) - memset_aligned(frame, 0, srv_page_size); + if (!zip.data); + else if (page) + memset_aligned(page, 0, srv_page_size); if (err == DB_PAGE_CORRUPTED) { @@ -3653,7 +3658,7 @@ dberr_t buf_page_t::read_complete(const fil_node_t &node) if (recovery && !recv_recover_page(node.space, this)) return DB_PAGE_CORRUPTED; - const bool ibuf_may_exist= frame && !recv_no_ibuf_operations && + const bool ibuf_may_exist= page && !recv_no_ibuf_operations && (!expected_id.space() || !is_predefined_tablespace(expected_id.space())) && fil_page_get_type(read_frame) == FIL_PAGE_INDEX && page_is_leaf(read_frame); diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index c1b4fdd4bf36a..90f204bbc34aa 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -99,13 +99,15 @@ bool buf_dblwr_t::create() return false; } + page_t *const trx_sys_page= trx_sys_block->page.frame; + if (mach_read_from_4(TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC + - trx_sys_block->page.frame) == + trx_sys_page) == TRX_SYS_DOUBLEWRITE_MAGIC_N) { /* The doublewrite buffer has already been created: just read in some numbers */ - init(TRX_SYS_DOUBLEWRITE + trx_sys_block->page.frame); + init(TRX_SYS_DOUBLEWRITE + trx_sys_page); mtr.commit(); return true; } @@ -139,8 +141,8 @@ bool buf_dblwr_t::create() user-specified location. */ } - byte *fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + - trx_sys_block->page.frame; + byte *const fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + + trx_sys_page; for (uint32_t prev_page_no= 0, i= 0, extent_size= FSP_EXTENT_SIZE; i < 2 * size + extent_size / 2; i++) { @@ -182,10 +184,10 @@ bool buf_dblwr_t::create() ut_a(id.page_no() == size); mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_BLOCK1 + - trx_sys_block->page.frame, id.page_no()); + trx_sys_page, id.page_no()); mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_REPEAT + - TRX_SYS_DOUBLEWRITE_BLOCK1 + trx_sys_block->page.frame, + TRX_SYS_DOUBLEWRITE_BLOCK1 + trx_sys_page, id.page_no()); } else if (i == size / 2 + size) @@ -193,44 +195,28 @@ bool buf_dblwr_t::create() ut_a(id.page_no() == 2 * size); mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_BLOCK2 + - trx_sys_block->page.frame, id.page_no()); + trx_sys_page, id.page_no()); mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_REPEAT + - TRX_SYS_DOUBLEWRITE_BLOCK2 + trx_sys_block->page.frame, - id.page_no()); + TRX_SYS_DOUBLEWRITE_BLOCK2 + trx_sys_page, id.page_no()); } else if (i > size / 2) ut_a(id.page_no() == prev_page_no + 1); - if (((i + 1) & 15) == 0) { - /* rw_locks can only be recursively x-locked 2048 times. (on 32 - bit platforms, (lint) 0 - (X_LOCK_DECR * 2049) is no longer a - negative number, and thus lock_word becomes like a shared lock). - For 4k page size this loop will lock the fseg header too many - times. Since this code is not done while any other threads are - active, restart the MTR occasionally. */ - mtr.commit(); - mtr.start(); - trx_sys_block= buf_dblwr_trx_sys_get(&mtr); - fseg_header= TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG + - trx_sys_block->page.frame; - } - prev_page_no= id.page_no(); } mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC + - trx_sys_block->page.frame, TRX_SYS_DOUBLEWRITE_MAGIC_N); + trx_sys_page, TRX_SYS_DOUBLEWRITE_MAGIC_N); mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_MAGIC + - TRX_SYS_DOUBLEWRITE_REPEAT + trx_sys_block->page.frame, + TRX_SYS_DOUBLEWRITE_REPEAT + trx_sys_page, TRX_SYS_DOUBLEWRITE_MAGIC_N); mtr.write<4>(*trx_sys_block, TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED + - trx_sys_block->page.frame, - TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N); + trx_sys_page, TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N); mtr.commit(); buf_flush_wait_flushed(mtr.commit_lsn()); diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 46129a037b0db..80b2af5035c0d 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -772,10 +772,11 @@ bool buf_page_t::flush(fil_space_t *space) ut_ad(space->referenced()); const auto s= state(); + page_t *write_frame= zip.data; const lsn_t lsn= mach_read_from_8(my_assume_aligned<8> - (FIL_PAGE_LSN + (zip.data ? zip.data : frame))); + (FIL_PAGE_LSN + (write_frame ? write_frame : frame))); ut_ad(lsn ? lsn >= oldest_modification() || oldest_modification() == 2 : space->purpose != FIL_TYPE_TABLESPACE); @@ -821,7 +822,6 @@ bool buf_page_t::flush(fil_space_t *space) Thus, it cannot be relocated or removed. */ buf_block_t *block= reinterpret_cast(this); - page_t *write_frame= zip.data; space->reacquire(); size_t size; @@ -829,8 +829,9 @@ bool buf_page_t::flush(fil_space_t *space) size_t orig_size; #endif buf_tmp_buffer_t *slot= nullptr; + byte *page= frame; - if (UNIV_UNLIKELY(!frame)) /* ROW_FORMAT=COMPRESSED */ + if (UNIV_UNLIKELY(!page)) /* ROW_FORMAT=COMPRESSED */ { ut_ad(!space->full_crc32()); ut_ad(!space->is_compressed()); /* not page_compressed */ @@ -844,7 +845,6 @@ bool buf_page_t::flush(fil_space_t *space) } else { - byte *page= frame; size= block->physical_size(); #if defined HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE || defined _WIN32 orig_size= size; diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 1c1e1150635c3..f3741a696be3f 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -597,7 +597,9 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) on the page, we do not acquire an s-latch on the page, this is to prevent deadlocks. The hash_lock is only protecting the buf_pool.page_hash for page i, not the bpage contents itself. */ - const byte *f= bpage->frame ? bpage->frame : bpage->zip.data; + const byte *f= bpage->frame; + if (UNIV_UNLIKELY(!f)) + f= bpage->zip.data; uint32_t prev= mach_read_from_4(my_assume_aligned<4>(f + FIL_PAGE_PREV)); uint32_t next= mach_read_from_4(my_assume_aligned<4>(f + FIL_PAGE_NEXT)); hash_lock.unlock_shared(); diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index 7b7fab82fd523..7b29a8767423f 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -65,32 +65,31 @@ dict_hdr_get_new_id( mtr.start(); buf_block_t* dict_hdr = dict_hdr_get(&mtr); + page_t* dict = dict_hdr->page.frame; if (table_id) { - id = mach_read_from_8(DICT_HDR + DICT_HDR_TABLE_ID - + dict_hdr->page.frame); + id = mach_read_from_8(DICT_HDR + DICT_HDR_TABLE_ID + dict); id++; mtr.write<8>(*dict_hdr, DICT_HDR + DICT_HDR_TABLE_ID - + dict_hdr->page.frame, id); + + dict, id); *table_id = id; } if (index_id) { - id = mach_read_from_8(DICT_HDR + DICT_HDR_INDEX_ID - + dict_hdr->page.frame); + id = mach_read_from_8(DICT_HDR + DICT_HDR_INDEX_ID + dict); id++; mtr.write<8>(*dict_hdr, DICT_HDR + DICT_HDR_INDEX_ID - + dict_hdr->page.frame, id); + + dict, id); *index_id = id; } if (space_id) { *space_id = mach_read_from_4(DICT_HDR + DICT_HDR_MAX_SPACE_ID - + dict_hdr->page.frame); + + dict); if (fil_assign_new_space_id(space_id)) { mtr.write<4>(*dict_hdr, DICT_HDR + DICT_HDR_MAX_SPACE_ID - + dict_hdr->page.frame, *space_id); + + dict, *space_id); } } @@ -125,25 +124,25 @@ dberr_t dict_create() buf_block_t* d = fseg_create(fil_system.sys_space, DICT_HDR + DICT_HDR_FSEG_HEADER, &mtr, &err); + page_t* dict; if (!d) { goto func_exit; } ut_a(d->page.id() == hdr_page_id); + dict = d->page.frame; /* Start counting row, table, index, and tree ids from DICT_HDR_FIRST_ID */ - mtr.write<8>(*d, DICT_HDR + DICT_HDR_ROW_ID + d->page.frame, + mtr.write<8>(*d, DICT_HDR + DICT_HDR_ROW_ID + dict, DICT_HDR_FIRST_ID); + mtr.write<8>(*d, DICT_HDR + DICT_HDR_TABLE_ID + dict, DICT_HDR_FIRST_ID); - mtr.write<8>(*d, DICT_HDR + DICT_HDR_TABLE_ID + d->page.frame, - DICT_HDR_FIRST_ID); - mtr.write<8>(*d, DICT_HDR + DICT_HDR_INDEX_ID + d->page.frame, + mtr.write<8>(*d, DICT_HDR + DICT_HDR_INDEX_ID + dict, DICT_HDR_FIRST_ID); - ut_ad(!mach_read_from_4(DICT_HDR + DICT_HDR_MAX_SPACE_ID - + d->page.frame)); + ut_ad(!mach_read_from_4(DICT_HDR + DICT_HDR_MAX_SPACE_ID + dict)); /* Obsolete, but we must initialize it anyway. */ - mtr.write<4>(*d, DICT_HDR + DICT_HDR_MIX_ID_LOW + d->page.frame, + mtr.write<4>(*d, DICT_HDR + DICT_HDR_MIX_ID_LOW + dict, DICT_HDR_FIRST_ID); /* Create the B-tree roots for the clustered indexes of the basic @@ -157,8 +156,7 @@ dberr_t dict_create() goto func_exit; } - mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLES + d->page.frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLES + dict, root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_UNIQUE, fil_system.sys_space, DICT_TABLE_IDS_ID, @@ -167,7 +165,7 @@ dberr_t dict_create() goto func_exit; } - mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLE_IDS + d->page.frame, + mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLE_IDS + dict, root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, @@ -177,8 +175,7 @@ dberr_t dict_create() goto func_exit; } - mtr.write<4>(*d, DICT_HDR + DICT_HDR_COLUMNS + d->page.frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_COLUMNS + dict, root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, fil_system.sys_space, DICT_INDEXES_ID, @@ -187,8 +184,7 @@ dberr_t dict_create() goto func_exit; } - mtr.write<4>(*d, DICT_HDR + DICT_HDR_INDEXES + d->page.frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_INDEXES + dict, root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, fil_system.sys_space, DICT_FIELDS_ID, @@ -197,8 +193,7 @@ dberr_t dict_create() goto func_exit; } - mtr.write<4>(*d, DICT_HDR + DICT_HDR_FIELDS + d->page.frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_FIELDS + dict, root_page_no); func_exit: mtr.commit(); return err ? err : dict_boot(); diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 8e5081ded8c32..8fb55fa5fdafa 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -869,7 +869,7 @@ uint32_t dict_drop_index_tree(btr_pcur_t *pcur, trx_t *trx, mtr_t *mtr) rec_2_get_field_end_info(rec, 1) != 8 + 8) goto rec_corrupted; - const byte *p= rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__TYPE, &len); + byte *p= rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__TYPE, &len); if (len != 4) goto rec_corrupted; const uint32_t type= mach_read_from_4(p); @@ -898,7 +898,7 @@ uint32_t dict_drop_index_tree(btr_pcur_t *pcur, trx_t *trx, mtr_t *mtr) static_assert(FIL_NULL == 0xffffffff, "compatibility"); static_assert(DICT_FLD__SYS_INDEXES__PAGE_NO == DICT_FLD__SYS_INDEXES__SPACE + 1, "compatibility"); - mtr->memset(btr_pcur_get_block(pcur), page_offset(p + 4), 4, 0xff); + mtr->memset(btr_pcur_get_block(pcur), p + 4, 4, 0xff); btr_free_if_exists(s, root_page_no, mach_read_from_8(rec + 8), mtr); } s->release(); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index d79d3eab8c3cd..8ce4fb8d46e4b 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -45,26 +45,6 @@ Created 4/24/1996 Heikki Tuuri #include "fts0opt.h" #include "row0vers.h" -/** Loads a table definition and also all its index definitions. - -Loads those foreign key constraints whose referenced table is already in -dictionary cache. If a foreign key constraint is not loaded, then the -referenced table is pushed into the output stack (fk_tables), if it is not -NULL. These tables must be subsequently loaded so that all the foreign -key constraints are loaded into memory. - -@param[in] name Table name in the db/tablename format -@param[in] ignore_err Error to be ignored when loading table - and its index definition -@param[out] fk_tables Related table names that must also be - loaded to ensure that all foreign key - constraints are loaded. -@return table, possibly with file_unreadable flag set -@retval nullptr if the table does not exist */ -static dict_table_t *dict_load_table_one(const span &name, - dict_err_ignore_t ignore_err, - dict_names_t &fk_tables); - /** Load an index definition from a SYS_INDEXES record to dict_index_t. @return error message @retval NULL on success */ @@ -2309,6 +2289,7 @@ dict_load_tablespace( ut_free(filepath); } +ATTRIBUTE_NOINLINE /** Loads a table definition and also all its index definitions. Loads those foreign key constraints whose referenced table is already in @@ -2625,13 +2606,16 @@ dict_load_table_on_id( dict_table_t* table = nullptr; if (btr_pcur_open_on_user_rec(&tuple, BTR_SEARCH_LEAF, &pcur, &mtr) - == DB_SUCCESS - && btr_pcur_is_on_user_rec(&pcur)) { + == DB_SUCCESS) { /*---------------------------------------------------*/ /* Now we have the record in the secondary index containing the table ID and NAME */ - const rec_t* rec = btr_pcur_get_rec(&pcur); check_rec: + const rec_t* rec = btr_pcur_get_rec(&pcur); + if (!page_rec_is_user_rec(btr_pcur_get_page(&pcur), rec)) { + goto func_exit; + } + field = rec_get_nth_field_old( rec, DICT_FLD__SYS_TABLE_IDS__ID, &len); ut_ad(len == 8); @@ -2643,22 +2627,17 @@ dict_load_table_on_id( table = dict_sys.load_table( {reinterpret_cast(field), len}, ignore_err); - if (table && table->id != table_id) { - ut_ad(rec_get_deleted_flag(rec, 0)); + if (!table || table->id != table_id) { + ut_ad(!table || rec_get_deleted_flag(rec, 0)); table = nullptr; - } - if (!table) { - while (btr_pcur_move_to_next(&pcur, &mtr)) { - rec = btr_pcur_get_rec(&pcur); - - if (page_rec_is_user_rec(rec)) { - goto check_rec; - } + if (btr_pcur_move_to_next(&pcur, &mtr)) { + goto check_rec; } } } } +func_exit: mtr.commit(); return table; } @@ -2683,7 +2662,7 @@ dict_load_sys_table( mem_heap_free(heap); } -MY_ATTRIBUTE((nonnull, warn_unused_result)) +MY_ATTRIBUTE((nonnull, warn_unused_result)) ATTRIBUTE_NOINLINE /********************************************************************//** Loads foreign key constraint col names (also for the referenced table). Members that must be set (and valid) in foreign: @@ -2736,8 +2715,6 @@ static dberr_t dict_load_foreign_cols(dict_foreign_t *foreign, trx_id_t trx_id) goto func_exit; } for (ulint i = 0; i < foreign->n_fields; i++) { - ut_a(btr_pcur_is_on_user_rec(&pcur)); - const rec_t* rec = btr_pcur_get_rec(&pcur); ulint len; const byte* field = rec_get_nth_field_old( diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 3d931c4a490e3..fd52e30ee8e40 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1100,11 +1100,12 @@ btr_cur_t::open_random_leaf(rec_offs *&offsets, mem_heap_t *&heap, mtr_t &mtr) mtr_s_lock_index(index(), &mtr); - if (index()->page == FIL_NULL) + auto offset= index()->page; + + if (offset == FIL_NULL) return DB_CORRUPTION; dberr_t err; - auto offset= index()->page; bool merge= false; ulint height= ULINT_UNDEFINED; @@ -1112,10 +1113,11 @@ btr_cur_t::open_random_leaf(rec_offs *&offsets, mem_heap_t *&heap, mtr_t &mtr) btr_block_get(*index(), offset, RW_S_LATCH, merge, &mtr, &err)) { page_cur.block= block; + page_cur.rec= block->page.frame; if (height == ULINT_UNDEFINED) { - height= btr_page_get_level(block->page.frame); + height= btr_page_get_level(page_cur.rec); if (height > BTR_MAX_LEVELS) return DB_CORRUPTION; @@ -1127,14 +1129,23 @@ btr_cur_t::open_random_leaf(rec_offs *&offsets, mem_heap_t *&heap, mtr_t &mtr) { mtr.rollback_to_savepoint(0, mtr.get_savepoint() - 1); got_leaf: - page_cur.rec= page_get_infimum_rec(block->page.frame); + page_cur.rec= page_get_infimum_rec(page_cur.rec); return DB_SUCCESS; } if (!--height) merge= !index()->is_clust(); - page_cur_open_on_rnd_user_rec(&page_cur); + if (const ulint n_recs= page_get_n_recs(page_cur.rec)) + { + page_cur.rec= page_rec_get_nth(page_cur.rec, + ut_rnd_interval(n_recs) + 1); + if (UNIV_UNLIKELY(!page_cur.rec)) + goto goto_infimum; + } + else + goto_infimum: + page_cur.rec= page_get_infimum_rec(page_cur.rec); offsets= rec_get_offsets(page_cur.rec, page_cur.index, offsets, 0, ULINT_UNDEFINED, &heap); @@ -1309,10 +1320,10 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index, page = btr_cur_get_page(&cursor); - rec = page_rec_get_next(cursor.page_cur.rec); + rec = page_rec_get_next(page, cursor.page_cur.rec); const ulint n_core = index->n_core_fields; - if (rec && !page_rec_is_supremum(rec)) { + if (rec && !page_rec_is_supremum(page, rec)) { not_empty_flag = 1; offsets_rec = rec_get_offsets(rec, index, offsets_rec, n_core, @@ -1324,10 +1335,11 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index, } } - while (!page_rec_is_supremum(rec)) { + while (!page_rec_is_supremum(page, rec)) { ulint matched_fields; - rec_t* next_rec = page_rec_get_next(rec); - if (!next_rec || page_rec_is_supremum(next_rec)) { + rec_t* next_rec = page_rec_get_next(page, rec); + if (!next_rec + || page_rec_is_supremum(page, next_rec)) { total_external_size += btr_rec_get_externally_stored_len( rec, offsets_rec); @@ -1501,17 +1513,18 @@ dict_stats_update_transient_for_index( goto invalid; } + const page_t* page = root->page.frame; mtr.x_lock_space(index->table->space); ulint dummy, size; index->stat_index_size = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF - + root->page.frame, &size, + + page, &size, &mtr) + fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_TOP - + root->page.frame, &dummy, + + page, &dummy, &mtr); mtr.commit(); @@ -1647,15 +1660,16 @@ static dberr_t page_cur_open_level(page_cur_t *page_cur, ulint level, uint32_t page= index->page; - for (ulint height = ULINT_UNDEFINED;; height--) + for (ulint height= ULINT_UNDEFINED;; height--) { - buf_block_t* block= + buf_block_t *block= btr_block_get(*index, page, RW_S_LATCH, !height && !index->is_clust(), mtr, &err); if (!block) break; - const uint32_t l= btr_page_get_level(block->page.frame); + const page_t *p= block->page.frame; + const uint32_t l= btr_page_get_level(p); if (height == ULINT_UNDEFINED) { @@ -1665,7 +1679,7 @@ static dberr_t page_cur_open_level(page_cur_t *page_cur, ulint level, if (UNIV_UNLIKELY(height < level)) return DB_CORRUPTION; } - else if (UNIV_UNLIKELY(height != l) || page_has_prev(block->page.frame)) + else if (UNIV_UNLIKELY(height != l) || page_has_prev(p)) { err= DB_CORRUPTION; break; @@ -1844,18 +1858,15 @@ dict_stats_analyze_index_level( bool rec_is_last_on_page; rec = btr_pcur_get_rec(&pcur); + const page_t *const page = btr_pcur_get_page(&pcur); /* If rec and prev_rec are on different pages, then prev_rec must have been copied, because we hold latch only on the page where rec resides. */ - if (prev_rec != NULL - && page_align(rec) != page_align(prev_rec)) { - - ut_a(prev_rec_is_copied); - } + ut_ad(!prev_rec || prev_rec_is_copied + || page == page_align(prev_rec)); - rec_is_last_on_page = - page_rec_is_supremum(page_rec_get_next_const(rec)); + rec_is_last_on_page = page_rec_is_last(page, rec); /* increment the pages counter at the end of each page */ if (rec_is_last_on_page) { @@ -1872,7 +1883,7 @@ dict_stats_analyze_index_level( if (level == 0 && !srv_stats_include_delete_marked - && rec_get_deleted_flag(rec, page_rec_is_comp(rec))) { + && rec_get_deleted_flag(rec, page_is_comp(page))) { if (rec_is_last_on_page && !prev_rec_is_copied && prev_rec != NULL) { @@ -2043,30 +2054,31 @@ Gets the pointer to the next non delete-marked record on the page. If all subsequent records are delete-marked, then this function will return the supremum record. @return pointer to next non delete-marked record or pointer to supremum */ -static -const rec_t* -page_rec_get_next_non_del_marked( -/*=============================*/ - const rec_t* rec) /*!< in: pointer to record */ +static const rec_t *page_rec_get_next_non_del_marked(const page_t *page, + const rec_t *rec) { - const page_t *const page= page_align(rec); - if (page_is_comp(page)) { - for (rec= page_rec_get_next_low(rec, TRUE); + for (rec= page_rec_get_next_low(page, rec, TRUE); rec && rec_get_deleted_flag(rec, TRUE); - rec= page_rec_get_next_low(rec, TRUE)); + rec= page_rec_get_next_low(page, rec, TRUE)); return rec ? rec : page + PAGE_NEW_SUPREMUM; } else { - for (rec= page_rec_get_next_low(rec, FALSE); + for (rec= page_rec_get_next_low(page, rec, FALSE); rec && rec_get_deleted_flag(rec, FALSE); - rec= page_rec_get_next_low(rec, FALSE)); + rec= page_rec_get_next_low(page, rec, FALSE)); return rec ? rec : page + PAGE_OLD_SUPREMUM; } } +static const rec_t *page_rec_get_next_const(const page_t *page, + const rec_t *rec) +{ + return page_rec_get_next(page, rec); +} + /** Scan a page, reading records from left to right and counting the number of distinct records (looking only at the first n_prefix columns) and the number of external pages pointed by records from this page. @@ -2089,7 +2101,7 @@ be big enough) to the number of externally stored pages which were encountered @return offsets1 or offsets2 (the offsets of *out_rec), or NULL if the page is empty and does not contain user records. */ -UNIV_INLINE +static rec_offs* dict_stats_scan_page( const rec_t** out_rec, @@ -2111,7 +2123,7 @@ dict_stats_scan_page( this memory heap should never be used. */ mem_heap_t* heap = NULL; ut_ad(!!n_core == page_is_leaf(page)); - const rec_t* (*get_next)(const rec_t*) + const rec_t* (*get_next)(const page_t*, const rec_t*) = !n_core || srv_stats_include_delete_marked ? page_rec_get_next_const : page_rec_get_next_non_del_marked; @@ -2122,9 +2134,9 @@ dict_stats_scan_page( *n_external_pages = 0; } - rec = get_next(page_get_infimum_rec(page)); + rec = get_next(page, page_get_infimum_rec(page)); - if (!rec || page_rec_is_supremum(rec)) { + if (!rec || page_rec_is_supremum(page, rec)) { /* the page is empty or contains only delete-marked records */ *n_diff = 0; *out_rec = NULL; @@ -2139,11 +2151,11 @@ dict_stats_scan_page( rec, offsets_rec); } - next_rec = get_next(rec); + next_rec = get_next(page, rec); *n_diff = 1; - while (next_rec && !page_rec_is_supremum(next_rec)) { + while (next_rec && !page_rec_is_supremum(page, next_rec)) { ulint matched_fields; @@ -2184,7 +2196,7 @@ dict_stats_scan_page( rec, offsets_rec); } - next_rec = get_next(next_rec); + next_rec = get_next(page, next_rec); } /* offsets1,offsets2 should have been big enough */ @@ -2246,7 +2258,7 @@ dict_stats_analyze_index_below_cur( rec_offs_set_n_alloc(offsets2, size); rec = btr_cur_get_rec(cur); - page = page_align(rec); + page = btr_cur_get_page(cur); ut_ad(!page_rec_is_leaf(rec)); offsets_rec = rec_get_offsets(rec, index, offsets1, 0, @@ -2443,7 +2455,7 @@ dict_stats_analyze_index_for_n_prefix( if (page_has_prev(page) || !btr_pcur_is_on_user_rec(&pcur) || btr_page_get_level(page) != n_diff_data->level - || first_rec != page_rec_get_next_const(page_get_infimum_rec(page)) + || first_rec != page_rec_get_first(page) || !(rec_get_info_bits(first_rec, page_is_comp(page)) & REC_INFO_MIN_REC_FLAG)) { return; @@ -2707,14 +2719,16 @@ static index_stats_t dict_stats_analyze_index(dict_index_t* index) DBUG_RETURN(result); } - uint16_t root_level = btr_page_get_level(root->page.frame); + const page_t *page = root->page.frame; + + uint16_t root_level = btr_page_get_level(page); mtr.x_lock_space(index->table->space); ulint dummy, size; result.index_size = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF - + root->page.frame, &size, &mtr) + + page, &size, &mtr) + fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_TOP - + root->page.frame, &dummy, &mtr); + + page, &dummy, &mtr); result.n_leaf_pages = size ? size : 1; const auto bulk_trx_id = index->table->bulk_trx_id; @@ -2821,7 +2835,8 @@ static index_stats_t dict_stats_analyze_index(dict_index_t* index) ut_ad(mtr.get_savepoint() == 1); buf_block_t *root = btr_root_block_get(index, RW_S_LATCH, &mtr, &err); - if (!root || root_level != btr_page_get_level(root->page.frame) + if (!root + || root_level != btr_page_get_level(root->page.frame) || index->table->bulk_trx_id != bulk_trx_id) { /* Just quit if the tree has changed beyond recognition here. The old stats from previous diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 12de62ac2bed6..5e908ccec97c7 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -399,7 +399,7 @@ void fil_space_crypt_t::write_page0(buf_block_t* block, mtr_t* mtr) ut_ad(b - start == 11 + MY_AES_BLOCK_SIZE); /* We must log also any unchanged bytes, because recovery will invoke fil_crypt_parse() based on this log record. */ - mtr->memcpy(*block, offset + MAGIC_SZ, b - start); + mtr->memcpy(*block, start, b - start); } /** Encrypt a buffer for non full checksum. @@ -1753,7 +1753,7 @@ fil_crypt_rotate_page( offset, &mtr, &sleeptime_ms)) { bool modified = false; - byte* frame = buf_block_get_frame(block); + byte* frame = block->page.frame; const lsn_t block_lsn = mach_read_from_8(FIL_PAGE_LSN + frame); uint kv = buf_page_get_key_version(frame, space->flags); diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 91e5b1531a22c..0d8b547ccbeea 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2683,7 +2683,8 @@ void fsp_flags_try_adjust(fil_space_t* space, ulint flags) if (buf_block_t* b = buf_page_get( page_id_t(space->id, 0), space->zip_size(), RW_X_LATCH, &mtr)) { - uint32_t f = fsp_header_get_flags(b->page.frame); + page_t* page = b->page.frame; + uint32_t f = fsp_header_get_flags(page); if (fil_space_t::full_crc32(f)) { goto func_exit; } @@ -2701,7 +2702,7 @@ void fsp_flags_try_adjust(fil_space_t* space, ulint flags) mtr.set_named_space(space); mtr.write<4,mtr_t::FORCED>(*b, FSP_HEADER_OFFSET + FSP_SPACE_FLAGS - + b->page.frame, flags); + + page, flags); } func_exit: mtr.commit(); diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 457fbed240874..e939d873242d8 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -155,7 +155,7 @@ inline void xdes_set_free(const buf_block_t &block, xdes_t *descr, ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); ut_ad(offset < FSP_EXTENT_SIZE); - ut_ad(page_align(descr) == block.page.frame); + ut_ad(block.page.is_physical_address(descr)); compile_time_assert(XDES_BITS_PER_PAGE == 2); compile_time_assert(XDES_FREE_BIT == 0); compile_time_assert(XDES_CLEAN_BIT == 1); @@ -227,7 +227,7 @@ inline void xdes_set_state(const buf_block_t &block, xdes_t *descr, ut_ad(state <= XDES_FSEG); ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); - ut_ad(page_align(descr) == block.page.frame); + ut_ad(block.page.is_physical_address(descr)); ut_ad(mach_read_from_4(descr + XDES_STATE) <= XDES_FSEG); mtr->write<1>(block, XDES_STATE + 3 + descr, state); } @@ -255,8 +255,7 @@ inline void xdes_init(const buf_block_t &block, xdes_t *descr, mtr_t *mtr) { ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); - mtr->memset(&block, uint16_t(descr - block.page.frame) + XDES_BITMAP, - XDES_SIZE - XDES_BITMAP, 0xff); + mtr->memset(&block, descr + XDES_BITMAP, XDES_SIZE - XDES_BITMAP, 0xff); xdes_set_state(block, descr, XDES_FREE, mtr); } @@ -275,23 +274,21 @@ fseg_mark_page_used(const fil_space_t *space, fseg_inode_t *seg_inode, buf_block_t *iblock, uint32_t page, xdes_t *descr, buf_block_t *xdes, mtr_t *mtr) { - ut_ad(fil_page_get_type(iblock->page.frame) == FIL_PAGE_INODE); + ut_ad(fil_page_get_type(page_align(seg_inode)) == FIL_PAGE_INODE); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); ut_ad(!memcmp(FSEG_MAGIC_N_BYTES, FSEG_MAGIC_N + seg_inode, 4)); ut_ad(!memcmp(seg_inode + FSEG_ID, descr + XDES_ID, 4)); - const uint16_t xoffset= uint16_t(descr - xdes->page.frame + XDES_FLST_NODE); - const uint16_t ioffset= uint16_t(seg_inode - iblock->page.frame); const uint32_t limit= space->free_limit; if (!xdes_get_n_used(descr)) { /* We move the extent from the free list to the NOT_FULL list */ - if (dberr_t err= flst_remove(iblock, uint16_t(FSEG_FREE + ioffset), - xdes, xoffset, limit, mtr)) + if (dberr_t err= flst_remove(iblock, seg_inode + FSEG_FREE, + xdes, descr + XDES_FLST_NODE, limit, mtr)) return err; - if (dberr_t err= flst_add_last(iblock, uint16_t(FSEG_NOT_FULL + ioffset), - xdes, xoffset, limit, mtr)) + if (dberr_t err= flst_add_last(iblock, seg_inode + FSEG_NOT_FULL, + xdes, descr + XDES_FLST_NODE, limit, mtr)) return err; } @@ -307,11 +304,11 @@ fseg_mark_page_used(const fil_space_t *space, if (xdes_is_full(descr)) { /* We move the extent from the NOT_FULL list to the FULL list */ - if (dberr_t err= flst_remove(iblock, uint16_t(FSEG_NOT_FULL + ioffset), - xdes, xoffset, limit, mtr)) + if (dberr_t err= flst_remove(iblock, FSEG_NOT_FULL + seg_inode, + xdes, descr + XDES_FLST_NODE, limit, mtr)) return err; - if (dberr_t err= flst_add_last(iblock, uint16_t(FSEG_FULL + ioffset), - xdes, xoffset, limit, mtr)) + if (dberr_t err= flst_add_last(iblock, FSEG_FULL + seg_inode, + xdes, descr + XDES_FLST_NODE, limit, mtr)) return err; mtr->write<4>(*iblock, seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used - FSP_EXTENT_SIZE); @@ -345,10 +342,11 @@ xdes_get_descriptor_with_space_hdr( ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); /* Read free limit and space size */ + page_t* page = header->page.frame; uint32_t limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + header->page.frame); + + page); uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + header->page.frame); + + page); ut_ad(limit == space->free_limit || (space->free_limit == 0 && (init_space @@ -372,6 +370,9 @@ xdes_get_descriptor_with_space_hdr( block = buf_page_get_gen(page_id_t(space->id, descr_page_no), zip_size, RW_SX_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, mtr, err); + if (block) { + page = block->page.frame; + } } if (desc_block) { @@ -381,7 +382,7 @@ xdes_get_descriptor_with_space_hdr( return block ? XDES_ARR_OFFSET + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset) - + block->page.frame + + page : nullptr; } @@ -452,31 +453,33 @@ static uint32_t xdes_get_offset(const xdes_t *descr) } /** Initialize a file page whose prior contents should be ignored. -@param[in,out] block buffer pool block */ -void fsp_apply_init_file_page(buf_block_t *block) +@param[in,out] block buffer pool block +@return the page frame */ +page_t *fsp_apply_init_file_page(buf_block_t *block) { - memset_aligned(block->page.frame, 0, srv_page_size); + page_t *page= block->page.frame; + memset_aligned(page, 0, srv_page_size); const page_id_t id(block->page.id()); - mach_write_to_4(block->page.frame + FIL_PAGE_OFFSET, id.page_no()); + mach_write_to_4(page + FIL_PAGE_OFFSET, id.page_no()); if (log_sys.is_physical()) - memset_aligned<8>(block->page.frame + FIL_PAGE_PREV, 0xff, 8); - mach_write_to_4(block->page.frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, - id.space()); + memset_aligned<8>(page + FIL_PAGE_PREV, 0xff, 8); + mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, id.space()); if (page_zip_des_t* page_zip= buf_block_get_page_zip(block)) { memset_aligned(page_zip->data, 0, page_zip_get_size(page_zip)); static_assert(FIL_PAGE_OFFSET == 4, "compatibility"); memcpy_aligned<4>(page_zip->data + FIL_PAGE_OFFSET, - block->page.frame + FIL_PAGE_OFFSET, 4); + page + FIL_PAGE_OFFSET, 4); if (log_sys.is_physical()) memset_aligned<8>(page_zip->data + FIL_PAGE_PREV, 0xff, 8); static_assert(FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID % 4 == 2, "not perfect alignment"); memcpy_aligned<2>(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, - block->page.frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4); + page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4); } + return page; } #ifdef UNIV_DEBUG @@ -528,40 +531,36 @@ dberr_t fsp_header_init(fil_space_t *space, uint32_t size, mtr_t *mtr) /* The prior contents of the file page should be ignored */ - fsp_init_file_page(space, block, mtr); + page_t* page = fsp_init_file_page(space, block, mtr); - mtr->write<2>(*block, block->page.frame + FIL_PAGE_TYPE, - FIL_PAGE_TYPE_FSP_HDR); + mtr->write<2>(*block, page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR); mtr->write<4,mtr_t::MAYBE_NOP>(*block, FSP_HEADER_OFFSET + FSP_SPACE_ID - + block->page.frame, space->id); - ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_NOT_USED - + block->page.frame)); + + page, space->id); + ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_NOT_USED + page)); /* recv_sys_t::parse() expects to find a WRITE record that covers all 4 bytes. Therefore, we must specify mtr_t::FORCED in order to avoid optimizing away any unchanged most significant bytes of FSP_SIZE. */ mtr->write<4,mtr_t::FORCED>(*block, FSP_HEADER_OFFSET + FSP_SIZE - + block->page.frame, size); + + page, size); ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + block->page.frame)); + + page)); if (auto f = space->flags & ~FSP_FLAGS_MEM_MASK) { mtr->write<4,mtr_t::FORCED>(*block, FSP_HEADER_OFFSET + FSP_SPACE_FLAGS - + block->page.frame, f); + + page, f); } ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_FRAG_N_USED - + block->page.frame)); + + page)); - flst_init(block, FSP_HEADER_OFFSET + FSP_FREE, mtr); - flst_init(block, FSP_HEADER_OFFSET + FSP_FREE_FRAG, mtr); - flst_init(block, FSP_HEADER_OFFSET + FSP_FULL_FRAG, mtr); - flst_init(block, FSP_HEADER_OFFSET + FSP_SEG_INODES_FULL, mtr); - flst_init(block, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE, mtr); + flst_init(block, FSP_HEADER_OFFSET + FSP_FREE + page, mtr); + flst_init(block, FSP_HEADER_OFFSET + FSP_FREE_FRAG + page, mtr); + flst_init(block, FSP_HEADER_OFFSET + FSP_FULL_FRAG + page, mtr); + flst_init(block, FSP_HEADER_OFFSET + FSP_SEG_INODES_FULL + page, mtr); + flst_init(block, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + page, mtr); - mtr->write<8>(*block, FSP_HEADER_OFFSET + FSP_SEG_ID - + block->page.frame, - 1U); + mtr->write<8>(*block, FSP_HEADER_OFFSET + FSP_SEG_ID + page, 1U); if (dberr_t err = fsp_fill_free_list(!is_system_tablespace(space->id), space, block, mtr)) { @@ -581,27 +580,27 @@ dberr_t fsp_header_init(fil_space_t *space, uint32_t size, mtr_t *mtr) /** Try to extend a single-table tablespace so that a page would fit in the data file. -@param[in,out] space tablespace -@param[in] page_no page number -@param[in,out] header tablespace header -@param[in,out] mtr mini-transaction +@param space tablespace +@param header tablespace header page descriptor +@param fsp_size the FSP_SIZE field in the header page +@param mtr mini-transaction +@param page_no page number @return true if success */ static ATTRIBUTE_COLD __attribute__((warn_unused_result)) bool fsp_try_extend_data_file_with_pages( fil_space_t* space, - uint32_t page_no, buf_block_t* header, - mtr_t* mtr) + byte* fsp_size, + mtr_t* mtr, + uint32_t page_no) { bool success; ulint size; ut_ad(!is_system_tablespace(space->id)); ut_d(space->modify_check(*mtr)); - - size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + header->page.frame); + size = mach_read_from_4(fsp_size); ut_ad(size == space->size_in_header); ut_a(page_no >= size); @@ -612,8 +611,7 @@ fsp_try_extend_data_file_with_pages( covers all 4 bytes. Therefore, we must specify mtr_t::FORCED in order to avoid optimizing away any unchanged most significant bytes of FSP_SIZE. */ - mtr->write<4,mtr_t::FORCED>(*header, FSP_HEADER_OFFSET + FSP_SIZE - + header->page.frame, space->size); + mtr->write<4,mtr_t::FORCED>(*header, fsp_size, space->size); space->size_in_header = space->size; return(success); @@ -659,15 +657,17 @@ static uint32_t fsp_get_pages_to_extend_ibd(unsigned physical_size, } /** Try to extend the last data file of a tablespace if it is auto-extending. -@param[in,out] space tablespace -@param[in,out] header tablespace header -@param[in,out] mtr mini-transaction +@param space tablespace +@param header tablespace header page descriptor +@param fsp_size the FSP_SIZE field in the header page +@param mtr mini-transaction @return number of pages added @retval 0 if the tablespace was not extended */ ATTRIBUTE_COLD __attribute__((nonnull)) static ulint -fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) +fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, + byte *fsp_size, mtr_t *mtr) { const char* OUT_OF_SPACE_MSG = "ran out of space. Please add another file or use" @@ -706,8 +706,7 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) return(0); } - uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + header->page.frame); + uint32_t size = mach_read_from_4(fsp_size); ut_ad(size == space->size_in_header); uint32_t size_increase; @@ -725,7 +724,8 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) if (size < extent_pages) { /* Let us first extend the file to extent_size */ if (!fsp_try_extend_data_file_with_pages( - space, extent_pages - 1, header, mtr)) { + space, header, fsp_size, mtr, + extent_pages - 1)) { return(0); } @@ -754,9 +754,7 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) covers all 4 bytes. Therefore, we must specify mtr_t::FORCED in order to avoid optimizing away any unchanged most significant bytes of FSP_SIZE. */ - mtr->write<4,mtr_t::FORCED>(*header, FSP_HEADER_OFFSET + FSP_SIZE - + header->page.frame, - space->size_in_header); + mtr->write<4,mtr_t::FORCED>(*header, fsp_size, space->size_in_header); return(size_increase); } @@ -765,15 +763,17 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) Data files created before MySQL 5.1.48 may contain garbage in FIL_PAGE_TYPE. In MySQL 3.23.53, only undo log pages and index pages were tagged. Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE. -@param[in] block block with invalid FIL_PAGE_TYPE +@param[in] block block descriptor +@param[in,out] page page with invalid FIL_PAGE_TYPE @param[in] type expected page type @param[in,out] mtr mini-transaction */ ATTRIBUTE_COLD -void fil_block_reset_type(const buf_block_t& block, ulint type, mtr_t* mtr) +void fil_block_reset_type(const buf_block_t &block, page_t *page, ulint type, + mtr_t *mtr) { ib::info() << "Resetting invalid page " << block.page.id() << " type " - << fil_page_get_type(block.page.frame) << " to " << type << "."; - mtr->write<2>(block, block.page.frame + FIL_PAGE_TYPE, type); + << fil_page_get_type(page) << " to " << type << "."; + mtr->write<2>(block, page + FIL_PAGE_TYPE, type); } /** Put new extents to the free list if there are free extents above the free @@ -796,11 +796,13 @@ fsp_fill_free_list( { ut_d(space->modify_check(*mtr)); + page_t *header_page= header->page.frame; + byte *fsp_size= FSP_HEADER_OFFSET + FSP_SIZE + header_page; + /* Check if we can fill free list from above the free list limit */ - uint32_t size= - mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + header->page.frame); + uint32_t size= mach_read_from_4(fsp_size); uint32_t limit= - mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + header->page.frame); + mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + header_page); ut_ad(size == space->size_in_header); ut_ad(limit == space->free_limit); @@ -821,7 +823,7 @@ fsp_fill_free_list( if (!skip_resize) { - fsp_try_extend_data_file(space, header, mtr); + fsp_try_extend_data_file(space, header, fsp_size, mtr); size= space->size_in_header; } } @@ -835,8 +837,8 @@ fsp_fill_free_list( { const bool init_xdes= !ut_2pow_remainder(i, physical_size); space->free_limit= i + extent_size; - mtr->write<4>(*header, FSP_HEADER_OFFSET + FSP_FREE_LIMIT + - header->page.frame, i + extent_size); + mtr->write<4>(*header, FSP_HEADER_OFFSET + FSP_FREE_LIMIT + header_page, + i + extent_size); if (init_xdes) { @@ -847,27 +849,22 @@ fsp_fill_free_list( if (i) { buf_block_t *f= buf_LRU_get_free_block(false); - buf_block_t *block= buf_page_create(space, static_cast(i), - zip_size, mtr, f); + buf_block_t *block= buf_page_create(space, i, zip_size, mtr, f); if (UNIV_UNLIKELY(block != f)) buf_pool.free_block(f); - fsp_init_file_page(space, block, mtr); - mtr->write<2>(*block, FIL_PAGE_TYPE + block->page.frame, - FIL_PAGE_TYPE_XDES); + page_t *page= fsp_init_file_page(space, block, mtr); + mtr->write<2>(*block, FIL_PAGE_TYPE + page, FIL_PAGE_TYPE_XDES); } if (space->purpose != FIL_TYPE_TEMPORARY) { buf_block_t *f= buf_LRU_get_free_block(false); buf_block_t *block= - buf_page_create(space, - static_cast(i + FSP_IBUF_BITMAP_OFFSET), - zip_size, mtr, f); + buf_page_create(space, i + FSP_IBUF_BITMAP_OFFSET, zip_size, mtr, f); if (UNIV_UNLIKELY(block != f)) buf_pool.free_block(f); - fsp_init_file_page(space, block, mtr); - mtr->write<2>(*block, FIL_PAGE_TYPE + block->page.frame, - FIL_PAGE_IBUF_BITMAP); + page_t *page= fsp_init_file_page(space, block, mtr); + mtr->write<2>(*block, FIL_PAGE_TYPE + page, FIL_PAGE_IBUF_BITMAP); } } @@ -882,10 +879,8 @@ fsp_fill_free_list( } if (xdes != header && !space->full_crc32()) - fil_block_check_type(*xdes, FIL_PAGE_TYPE_XDES, mtr); + fil_block_check_type(*xdes, page_align(descr), FIL_PAGE_TYPE_XDES, mtr); xdes_init(*xdes, descr, mtr); - const uint16_t xoffset= - static_cast(descr - xdes->page.frame + XDES_FLST_NODE); if (UNIV_UNLIKELY(init_xdes)) { /* The first page in the extent is a descriptor page and the @@ -893,17 +888,19 @@ fsp_fill_free_list( xdes_set_free(*xdes, descr, 0, mtr); xdes_set_free(*xdes, descr, FSP_IBUF_BITMAP_OFFSET, mtr); xdes_set_state(*xdes, descr, XDES_FREE_FRAG, mtr); - if (dberr_t err= flst_add_last(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG, - xdes, xoffset, space->free_limit, mtr)) + if (dberr_t err= + flst_add_last(header, + FSP_HEADER_OFFSET + FSP_FREE_FRAG + header_page, + xdes, descr + XDES_FLST_NODE, space->free_limit, mtr)) return err; - byte *n_used= FSP_HEADER_OFFSET + FSP_FRAG_N_USED + header->page.frame; + byte *n_used= FSP_HEADER_OFFSET + FSP_FRAG_N_USED + header_page; mtr->write<4>(*header, n_used, 2U + mach_read_from_4(n_used)); } else { if (dberr_t err= - flst_add_last(header, FSP_HEADER_OFFSET + FSP_FREE, - xdes, xoffset, space->free_limit, mtr)) + flst_add_last(header, FSP_HEADER_OFFSET + FSP_FREE + header_page, + xdes, descr + XDES_FLST_NODE, space->free_limit, mtr)) return err; count++; } @@ -944,15 +941,17 @@ static xdes_t *fsp_alloc_free_extent(fil_space_t *space, uint32_t hint, } if (desc_block != header && !space->full_crc32()) { - fil_block_check_type(*desc_block, FIL_PAGE_TYPE_XDES, mtr); + fil_block_check_type(*desc_block, page_align(descr), + FIL_PAGE_TYPE_XDES, mtr); } + byte* fsp_free = FSP_HEADER_OFFSET + FSP_FREE + header->page.frame; + if (xdes_get_state(descr) == XDES_FREE) { /* Ok, we can take this extent */ } else { /* Take the first extent in the free list */ - first = flst_get_first(FSP_HEADER_OFFSET + FSP_FREE - + header->page.frame); + first = flst_get_first(fsp_free); if (first.page >= space->free_limit) { if (first.page != FIL_NULL) { @@ -964,8 +963,7 @@ static xdes_t *fsp_alloc_free_extent(fil_space_t *space, uint32_t hint, goto corrupted; } - first = flst_get_first(FSP_HEADER_OFFSET + FSP_FREE - + header->page.frame); + first = flst_get_first(fsp_free); if (first.page == FIL_NULL) { *err = DB_OUT_OF_FILE_SPACE; return nullptr; /* No free extents left */ @@ -990,10 +988,8 @@ static xdes_t *fsp_alloc_free_extent(fil_space_t *space, uint32_t hint, } } - *err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE, desc_block, - static_cast(descr - desc_block->page.frame - + XDES_FLST_NODE), - space->free_limit, mtr); + *err = flst_remove(header, fsp_free, desc_block, + descr + XDES_FLST_NODE, space->free_limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) { return nullptr; } @@ -1022,21 +1018,22 @@ fsp_alloc_from_free_frag(buf_block_t *header, buf_block_t *xdes, xdes_t *descr, return DB_CORRUPTION; xdes_set_free(*xdes, descr, bit, mtr); + page_t *header_page= header->page.frame; /* Update the FRAG_N_USED field */ - byte *n_used_p= FSP_HEADER_OFFSET + FSP_FRAG_N_USED + header->page.frame; - uint32_t n_used = mach_read_from_4(n_used_p) + 1; + byte *n_used_p= FSP_HEADER_OFFSET + FSP_FRAG_N_USED + header_page; + uint32_t n_used= mach_read_from_4(n_used_p) + 1; if (xdes_is_full(descr)) { const uint32_t limit= space->free_limit; /* The fragment is full: move it to another list */ - const uint16_t xoffset= - static_cast(descr - xdes->page.frame + XDES_FLST_NODE); - if (dberr_t err= flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG, - xdes, xoffset, limit, mtr)) + if (dberr_t err= flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG + + header_page, xdes, + descr + XDES_FLST_NODE, limit, mtr)) return err; - if (dberr_t err= flst_add_last(header, FSP_HEADER_OFFSET + FSP_FULL_FRAG, - xdes, xoffset, limit, mtr)) + if (dberr_t err= flst_add_last(header, FSP_HEADER_OFFSET + FSP_FULL_FRAG + + header_page, xdes, + descr + XDES_FLST_NODE, limit, mtr)) return err; xdes_set_state(*xdes, descr, XDES_FULL_FRAG, mtr); n_used-= FSP_EXTENT_SIZE; @@ -1082,6 +1079,7 @@ buf_block_t *fsp_alloc_free_page(fil_space_t *space, uint32_t hint, buf_block_t *block= fsp_get_header(space, mtr, err); if (!block) return block; + page_t *page= block->page.frame; buf_block_t *xdes; /* Get the hinted descriptor */ @@ -1098,8 +1096,7 @@ buf_block_t *fsp_alloc_free_page(fil_space_t *space, uint32_t hint, else { /* Else take the first extent in free_frag list */ - fil_addr_t first = flst_get_first(FSP_HEADER_OFFSET + FSP_FREE_FRAG + - block->page.frame); + fil_addr_t first= flst_get_first(FSP_HEADER_OFFSET + FSP_FREE_FRAG + page); if (first.page >= space->free_limit) { if (first.page != FIL_NULL) @@ -1113,9 +1110,8 @@ buf_block_t *fsp_alloc_free_page(fil_space_t *space, uint32_t hint, descr= fsp_alloc_free_extent(space, hint, &xdes, mtr, err); if (!descr) return nullptr; - *err= flst_add_last(block, FSP_HEADER_OFFSET + FSP_FREE_FRAG, xdes, - static_cast(descr - xdes->page.frame + - XDES_FLST_NODE), + *err= flst_add_last(block, FSP_HEADER_OFFSET + FSP_FREE_FRAG + page, + xdes, descr + XDES_FLST_NODE, space->free_limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) return nullptr; @@ -1151,8 +1147,8 @@ buf_block_t *fsp_alloc_free_page(fil_space_t *space, uint32_t hint, } uint32_t page_no= xdes_get_offset(descr) + free; - uint32_t space_size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + - block->page.frame); + byte *fsp_size= FSP_HEADER_OFFSET + FSP_SIZE + page; + uint32_t space_size = mach_read_from_4(fsp_size); ut_ad(space_size == space->size_in_header || (space->id == TRX_SYS_SPACE && srv_startup_is_before_trx_rollback_phase)); @@ -1171,7 +1167,8 @@ buf_block_t *fsp_alloc_free_page(fil_space_t *space, uint32_t hint, goto corrupted; } - if (!fsp_try_extend_data_file_with_pages(space, page_no, block, mtr)) + if (!fsp_try_extend_data_file_with_pages(space, block, fsp_size, mtr, + page_no)) { *err= DB_OUT_OF_FILE_SPACE; return nullptr; @@ -1215,9 +1212,9 @@ static dberr_t fsp_free_extent(fil_space_t* space, page_no_t offset, xdes_init(*xdes, descr, mtr); space->free_len++; - return flst_add_last(block, FSP_HEADER_OFFSET + FSP_FREE, - xdes, static_cast(descr - xdes->page.frame + - XDES_FLST_NODE), + return flst_add_last(block, + FSP_HEADER_OFFSET + FSP_FREE + block->page.frame, + xdes, descr + XDES_FLST_NODE, space->free_limit, mtr); } @@ -1267,34 +1264,33 @@ static dberr_t fsp_free_page(fil_space_t *space, page_no_t offset, mtr_t *mtr) return DB_CORRUPTION; } - frag_n_used = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FRAG_N_USED - + header->page.frame); - - const uint16_t xoffset= static_cast(descr - xdes->page.frame - + XDES_FLST_NODE); + page_t* header_page = header->page.frame; + byte* fsp_frag_n_used = FSP_HEADER_OFFSET + FSP_FRAG_N_USED + + header_page; + frag_n_used = mach_read_from_4(fsp_frag_n_used); const uint32_t limit = space->free_limit; if (state == XDES_FULL_FRAG) { /* The fragment was full: move it to another list */ - err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FULL_FRAG, - xdes, xoffset, limit, mtr); + err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FULL_FRAG + + header_page, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } - err = flst_add_last(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG, - xdes, xoffset, limit, mtr); + err = flst_add_last(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG + + header_page, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } xdes_set_state(*xdes, descr, XDES_FREE_FRAG, mtr); - mtr->write<4>(*header, FSP_HEADER_OFFSET + FSP_FRAG_N_USED - + header->page.frame, + mtr->write<4>(*header, fsp_frag_n_used, frag_n_used + FSP_EXTENT_SIZE - 1); } else if (UNIV_UNLIKELY(!frag_n_used)) { return DB_CORRUPTION; } else { - mtr->write<4>(*header, FSP_HEADER_OFFSET + FSP_FRAG_N_USED - + header->page.frame, frag_n_used - 1); + mtr->write<4>(*header, fsp_frag_n_used, frag_n_used - 1); } mtr->free(*space, static_cast(offset)); @@ -1303,8 +1299,9 @@ static dberr_t fsp_free_page(fil_space_t *space, page_no_t offset, mtr_t *mtr) if (!xdes_get_n_used(descr)) { /* The extent has become free: move it to another list */ - err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG, - xdes, xoffset, limit, mtr); + err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG + + header_page, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (err == DB_SUCCESS) { err = fsp_free_extent(space, offset, mtr); } @@ -1372,12 +1369,15 @@ fsp_seg_inode_page_find_free(const page_t *page, ulint i, ulint physical_size) MY_ATTRIBUTE((nonnull, warn_unused_result)) /** Allocate a file segment inode page. -@param[in,out] space tablespace -@param[in,out] header tablespace header -@param[in,out] mtr mini-transaction +@param space tablespace +@param header tablespace header +@param header_page header->page.frame +@param mtr mini-transaction @return error code */ static dberr_t fsp_alloc_seg_inode_page(fil_space_t *space, - buf_block_t *header, mtr_t *mtr) + buf_block_t *header, + page_t *header_page, + mtr_t *mtr) { ut_ad(header->page.id().space() == space->id); dberr_t err; @@ -1387,38 +1387,42 @@ static dberr_t fsp_alloc_seg_inode_page(fil_space_t *space, return err; ut_ad(block->page.lock.not_recursive()); + page_t *page= block->page.frame; - mtr->write<2>(*block, block->page.frame + FIL_PAGE_TYPE, FIL_PAGE_INODE); + mtr->write<2>(*block, page + FIL_PAGE_TYPE, FIL_PAGE_INODE); #ifdef UNIV_DEBUG - const byte *inode= FSEG_ID + FSEG_ARR_OFFSET + block->page.frame; + const byte *inode= FSEG_ID + FSEG_ARR_OFFSET + page; for (ulint i= FSP_SEG_INODES_PER_PAGE(space->physical_size()); i--; inode += FSEG_INODE_SIZE) ut_ad(!mach_read_from_8(inode)); #endif - return flst_add_last(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE, - block, FSEG_INODE_PAGE_NODE, space->free_limit, mtr); + return flst_add_last(header, + FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + header_page, + block, FSEG_INODE_PAGE_NODE + page, + space->free_limit, mtr); } MY_ATTRIBUTE((nonnull, warn_unused_result)) /** Allocate a file segment inode. -@param[in,out] space tablespace -@param[in,out] header tablespace header -@param[out] iblock segment inode page -@param[in,out] mtr mini-transaction -@param[out] err error code +@param space tablespace +@param header tablespace header +@param header_page header->page.frame +@param mtr mini-transaction +@param iblock segment inode page +@param err error code @return segment inode @retval nullptr on failure */ static fseg_inode_t* -fsp_alloc_seg_inode(fil_space_t *space, buf_block_t *header, - buf_block_t **iblock, mtr_t *mtr, dberr_t *err) +fsp_alloc_seg_inode(fil_space_t *space, + buf_block_t *header, page_t *header_page, mtr_t *mtr, + buf_block_t **iblock, dberr_t *err) { /* Allocate a new segment inode page if needed. */ - if (!flst_get_len(FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + - header->page.frame)) + if (!flst_get_len(FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + header_page)) { - *err= fsp_alloc_seg_inode_page(space, header, mtr); + *err= fsp_alloc_seg_inode_page(space, header, header_page, mtr); if (*err != DB_SUCCESS) return nullptr; } @@ -1427,7 +1431,7 @@ fsp_alloc_seg_inode(fil_space_t *space, buf_block_t *header, { space->id, mach_read_from_4(FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + FLST_FIRST + - FIL_ADDR_PAGE + header->page.frame) + FIL_ADDR_PAGE + header_page) }; buf_block_t *block= @@ -1436,31 +1440,35 @@ fsp_alloc_seg_inode(fil_space_t *space, buf_block_t *header, if (!block) return nullptr; + page_t *page= block->page.frame; + if (!space->full_crc32()) - fil_block_check_type(*block, FIL_PAGE_INODE, mtr); + fil_block_check_type(*block, page, FIL_PAGE_INODE, mtr); const ulint physical_size= space->physical_size(); - ulint n= fsp_seg_inode_page_find_free(block->page.frame, 0, physical_size); + ulint n= fsp_seg_inode_page_find_free(page, 0, physical_size); if (UNIV_UNLIKELY(n >= FSP_SEG_INODES_PER_PAGE(physical_size))) { *err= DB_CORRUPTION; return nullptr; } - fseg_inode_t *inode= fsp_seg_inode_page_get_nth_inode(block->page.frame, n); + fseg_inode_t *inode= fsp_seg_inode_page_get_nth_inode(page, n); - if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(block->page.frame, n + 1, + if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1, physical_size)) { /* There are no other unused headers left on the page: move it to another list */ const uint32_t limit= space->free_limit; - *err= flst_remove(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE, - block, FSEG_INODE_PAGE_NODE, limit, mtr); + *err= flst_remove(header, + FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + header_page, + block, FSEG_INODE_PAGE_NODE + page, limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) return nullptr; - *err= flst_add_last(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FULL, - block, FSEG_INODE_PAGE_NODE, limit, mtr); + *err= flst_add_last(header, + FSP_HEADER_OFFSET + FSP_SEG_INODES_FULL + header_page, + block, FSEG_INODE_PAGE_NODE + page, limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) return nullptr; } @@ -1481,41 +1489,46 @@ static void fsp_free_seg_inode(fil_space_t *space, fseg_inode_t *inode, buf_block_t *iblock, mtr_t *mtr) { ut_d(space->modify_check(*mtr)); - - dberr_t err; - buf_block_t *header= fsp_get_header(space, mtr, &err); - if (!header) - return; if (UNIV_UNLIKELY(memcmp(FSEG_MAGIC_N_BYTES, FSEG_MAGIC_N + inode, 4))) { space->set_corrupted(); return; } + dberr_t err; + buf_block_t *header= fsp_get_header(space, mtr, &err); + if (!header) + return; + page_t *header_page= header->page.frame, *ipage= page_align(inode); + const ulint physical_size= space->physical_size(); const uint32_t limit= space->free_limit; - if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(iblock->page.frame, 0, - physical_size)) + if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(ipage, 0, physical_size)) { /* Move the page to another list */ - if (flst_remove(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FULL, - iblock, FSEG_INODE_PAGE_NODE, limit, mtr) != DB_SUCCESS) + if (flst_remove(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FULL + + header_page, + iblock, ipage + FSEG_INODE_PAGE_NODE, limit, mtr) != + DB_SUCCESS) return; - if (flst_add_last(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE, - iblock, FSEG_INODE_PAGE_NODE, limit, mtr) != DB_SUCCESS) + if (flst_add_last(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + + header_page, + iblock, ipage + FSEG_INODE_PAGE_NODE, limit, mtr) != + DB_SUCCESS) return; } - mtr->memset(iblock, page_offset(inode) + FSEG_ID, FSEG_INODE_SIZE, 0); + mtr->memset(iblock, inode + FSEG_ID, FSEG_INODE_SIZE, 0); - if (ULINT_UNDEFINED != fsp_seg_inode_page_find_used(iblock->page.frame, - physical_size)) + if (ULINT_UNDEFINED != fsp_seg_inode_page_find_used(ipage, physical_size)) return; /* There are no other used headers left on the page: free it */ - if (flst_remove(header, FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE, - iblock, FSEG_INODE_PAGE_NODE, limit, mtr) == DB_SUCCESS) + if (flst_remove(header, + FSP_HEADER_OFFSET + FSP_SEG_INODES_FREE + header_page, + iblock, ipage + FSEG_INODE_PAGE_NODE, limit, mtr) == + DB_SUCCESS) fsp_free_page(space, iblock->page.id().page_no(), mtr); } @@ -1696,15 +1709,17 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, dberr_t *err, ut_ad(!block || block->page.id().space() == space->id); buf_block_t* header = fsp_get_header(space, mtr, err); + buf_block_t* iblock; + page_t* header_page; if (!header) { block = nullptr; goto funct_exit; } - - buf_block_t* iblock; + header_page = header->page.frame; inode_alloc: - inode = fsp_alloc_seg_inode(space, header, &iblock, mtr, err); + inode = fsp_alloc_seg_inode(space, header, header_page, mtr, &iblock, + err); if (!inode) { block = nullptr; @@ -1736,10 +1751,10 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, dberr_t *err, value in space header */ seg_id = mach_read_from_8(FSP_HEADER_OFFSET + FSP_SEG_ID - + header->page.frame); + + header_page); mtr->write<8>(*header, - FSP_HEADER_OFFSET + FSP_SEG_ID + header->page.frame, + FSP_HEADER_OFFSET + FSP_SEG_ID + header_page, seg_id + 1); mtr->write<8>(*iblock, inode + FSEG_ID, seg_id); ut_ad(!mach_read_from_4(inode + FSEG_NOT_FULL_N_USED)); @@ -1751,9 +1766,9 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, dberr_t *err, mtr->memcpy(*iblock, inode + FSEG_MAGIC_N, FSEG_MAGIC_N_BYTES, 4); compile_time_assert(FSEG_FRAG_SLOT_SIZE == 4); compile_time_assert(FIL_NULL == 0xffffffff); - mtr->memset(iblock, - uint16_t(inode - iblock->page.frame) + FSEG_FRAG_ARR, + mtr->memset(iblock, inode + FSEG_FRAG_ARR, FSEG_FRAG_SLOT_SIZE * FSEG_FRAG_ARR_N_SLOTS, 0xff); + page_t* page; if (!block) { page_alloc: @@ -1769,22 +1784,25 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, dberr_t *err, goto reserve_extent; } + page = block->page.frame; ut_d(const auto x = block->page.lock.x_lock_count()); ut_ad(x || block->page.lock.not_recursive()); ut_ad(x <= 2); - ut_ad(!fil_page_get_type(block->page.frame)); - mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->page.frame, + ut_ad(!fil_page_get_type(page)); + mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + page, FIL_PAGE_TYPE_SYS); + } else { + page = block->page.frame; } - mtr->write<2>(*block, byte_offset + FSEG_HDR_OFFSET - + block->page.frame, page_offset(inode)); + mtr->write<2>(*block, byte_offset + FSEG_HDR_OFFSET + page, + inode - iblock->page.frame); - mtr->write<4>(*block, byte_offset + FSEG_HDR_PAGE_NO - + block->page.frame, iblock->page.id().page_no()); + mtr->write<4>(*block, byte_offset + FSEG_HDR_PAGE_NO + page, + iblock->page.id().page_no()); mtr->write<4,mtr_t::MAYBE_NOP>(*block, byte_offset + FSEG_HDR_SPACE - + block->page.frame, space->id); + + page, space->id); funct_exit: if (!has_done_reservation && reserved_extent) { @@ -1827,7 +1845,7 @@ ulint fseg_n_reserved_pages(const buf_block_t &block, const fseg_header_t *header, ulint *used, mtr_t *mtr) { - ut_ad(page_align(header) == block.page.frame); + ut_ad(block.page.is_physical_address(header)); buf_block_t *iblock; if (fseg_inode_t *inode= fseg_inode_try_get(header, block.page.id().space(), block.zip_size(), @@ -1841,12 +1859,12 @@ MY_ATTRIBUTE((nonnull, warn_unused_result)) 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 from the hint onward. -@param[in] inode segment inode +@param[in,out] inode segment inode @param[in,out] iblock segment inode page @param[in] space tablespace @param[in] hint hint which extent would be good as the first extent @param[in,out] mtr mini-transaction */ -static dberr_t fseg_fill_free_list(const fseg_inode_t *inode, +static dberr_t fseg_fill_free_list(fseg_inode_t *inode, buf_block_t *iblock, fil_space_t *space, uint32_t hint, mtr_t *mtr) { @@ -1884,12 +1902,8 @@ static dberr_t fseg_fill_free_list(const fseg_inode_t *inode, return err; if (dberr_t err= - flst_add_last(iblock, - static_cast(inode - iblock->page.frame + - FSEG_FREE), xdes, - static_cast(descr - xdes->page.frame + - XDES_FLST_NODE), - space->free_limit, mtr)) + flst_add_last(iblock, inode + FSEG_FREE, xdes, + descr + XDES_FLST_NODE, space->free_limit, mtr)) return err; xdes_set_state(*xdes, descr, XDES_FSEG, mtr); mtr->memcpy(*xdes, descr + XDES_ID, inode + FSEG_ID, 8); @@ -1903,7 +1917,7 @@ MY_ATTRIBUTE((nonnull, warn_unused_result)) the segment, then tries to allocate from the space free list. NOTE that the extent returned still resides in the segment free list, it is not yet taken off it! -@param[in] inode segment inode +@param[in,out] inode segment inode @param[in,out] iblock segment inode page @param[out] xdes extent descriptor page @param[in,out] space tablespace @@ -1913,7 +1927,7 @@ not yet taken off it! static xdes_t* fseg_alloc_free_extent( - const fseg_inode_t* inode, + fseg_inode_t* inode, buf_block_t* iblock, buf_block_t** xdes, fil_space_t* space, @@ -1924,7 +1938,10 @@ fseg_alloc_free_extent( ut_ad(!memcmp(FSEG_MAGIC_N_BYTES, FSEG_MAGIC_N + inode, 4)); ut_d(space->modify_check(*mtr)); - if (UNIV_UNLIKELY(page_offset(inode) < FSEG_ARR_OFFSET)) + const size_t end= space->physical_size() - (XDES_SIZE + FIL_PAGE_DATA_END); + const ptrdiff_t d= inode - iblock->page.frame; + + if (UNIV_UNLIKELY(d < FSEG_ARR_OFFSET || size_t(d) > end)) { corrupted: *err= DB_CORRUPTION; @@ -1937,8 +1954,7 @@ fseg_alloc_free_extent( const fil_addr_t first= flst_get_first(inode + FSEG_FREE); if (first.page >= space->free_limit || first.boffset < FSP_HEADER_OFFSET + FSP_HEADER_SIZE || - first.boffset >= space->physical_size() - - (XDES_SIZE + FIL_PAGE_DATA_END)) + first.boffset >= end) goto corrupted; /* Segment free list is not empty, allocate from it */ @@ -1950,12 +1966,8 @@ fseg_alloc_free_extent( return descr; xdes_set_state(**xdes, descr, XDES_FSEG, mtr); mtr->memcpy(**xdes, descr + XDES_ID, inode + FSEG_ID, 8); - *err= flst_add_last(iblock, - static_cast(inode - iblock->page.frame + - FSEG_FREE), *xdes, - static_cast(descr - (*xdes)->page.frame + - XDES_FLST_NODE), - space->free_limit, mtr); + *err= flst_add_last(iblock, inode + FSEG_FREE, *xdes, + descr + XDES_FLST_NODE, space->free_limit, mtr); if (UNIV_LIKELY(*err != DB_SUCCESS)) return nullptr; /* Try to fill the segment free list */ @@ -2091,13 +2103,8 @@ fseg_alloc_free_page_low( mtr->write<8,mtr_t::MAYBE_NOP>(*xdes, ret_descr + XDES_ID, seg_id); *err = flst_add_last( - iblock, - static_cast(seg_inode - iblock->page.frame - + FSEG_FREE), xdes, - static_cast(ret_descr - - xdes->page.frame - + XDES_FLST_NODE), - space->free_limit, mtr); + iblock, seg_inode + FSEG_FREE, xdes, + ret_descr + XDES_FLST_NODE, space->free_limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) { return nullptr; } @@ -2222,7 +2229,8 @@ fseg_alloc_free_page_low( } if (!fsp_try_extend_data_file_with_pages( - space, ret_page, header, mtr)) { + space, header, FSP_HEADER_OFFSET + FSP_SIZE + + header->page.frame, mtr, ret_page)) { /* No disk space left */ ut_ad(!has_done_reservation); return nullptr; @@ -2295,7 +2303,8 @@ fseg_alloc_free_page_general( return nullptr; } if (!space->full_crc32()) { - fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr); + fil_block_check_type(*iblock, page_align(inode), + FIL_PAGE_INODE, mtr); } if (!has_done_reservation) { @@ -2330,19 +2339,21 @@ of a single-table tablespace, and they are also physically initialized to the data file. That is we have already extended the data file so that those pages are inside the data file. If not, this function extends the tablespace with pages. -@param[in,out] space tablespace -@param[in,out] header tablespace header, x-latched -@param[in] size tablespace size in pages, less than FSP_EXTENT_SIZE -@param[in,out] mtr mini-transaction -@param[in] n_pages number of pages to reserve +@param space tablespace +@param header tablespace header, x-latched +@param fsp_size the FSP_SIZE field in the header page +@param size tablespace size in pages, less than FSP_EXTENT_SIZE +@param mtr mini-transaction +@param n_pages number of pages to reserve @return error code */ static dberr_t fsp_reserve_free_pages( fil_space_t* space, buf_block_t* header, - ulint size, + byte* fsp_size, mtr_t* mtr, + ulint size, uint32_t n_pages) { ut_ad(space != fil_system.sys_space && space != fil_system.temp_space); @@ -2358,8 +2369,8 @@ fsp_reserve_free_pages( return DB_SUCCESS; if (n_used > size) return DB_CORRUPTION; - return fsp_try_extend_data_file_with_pages(space, n_used + n_pages - 1, - header, mtr) + return fsp_try_extend_data_file_with_pages(space, header, fsp_size, mtr, + n_used + n_pages - 1) ? DB_SUCCESS : DB_OUT_OF_FILE_SPACE; } @@ -2427,25 +2438,26 @@ fsp_reserve_free_extents( if (!header) { return err; } + page_t* header_page = header->page.frame; try_again: - uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + header->page.frame); + byte* fsp_size = FSP_HEADER_OFFSET + FSP_SIZE + header_page; + uint32_t size = mach_read_from_4(fsp_size); ut_ad(size == space->size_in_header); if (size < extent_size && n_pages < extent_size / 2) { /* Use different rules for small single-table tablespaces */ *n_reserved = 0; - return fsp_reserve_free_pages(space, header, size, - mtr, n_pages); + return fsp_reserve_free_pages(space, header, fsp_size, mtr, + size, n_pages); } uint32_t n_free_list_ext = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE - + header->page.frame); + + header_page); ut_ad(space->free_len == n_free_list_ext); uint32_t free_limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT - + header->page.frame); + + header_page); ut_ad(space->free_limit == free_limit); /* Below we play safe when counting free extents above the free limit: @@ -2502,7 +2514,7 @@ fsp_reserve_free_extents( return DB_SUCCESS; } try_to_extend: - if (fsp_try_extend_data_file(space, header, mtr)) { + if (fsp_try_extend_data_file(space, header, fsp_size, mtr)) { goto try_again; } @@ -2511,7 +2523,8 @@ fsp_reserve_free_extents( MY_ATTRIBUTE((nonnull, warn_unused_result)) /** Frees a single page of a segment. -@param[in] seg_inode segment inode +@param[in,out] iblock inode block descriptor +@param[in,out] seg_inode segment inode @param[in,out] space tablespace @param[in] offset page number @param[in,out] mtr mini-transaction @@ -2520,8 +2533,8 @@ MY_ATTRIBUTE((nonnull, warn_unused_result)) static dberr_t fseg_free_page_low( - fseg_inode_t* seg_inode, buf_block_t* iblock, + fseg_inode_t* seg_inode, fil_space_t* space, page_no_t offset, mtr_t* mtr @@ -2532,7 +2545,7 @@ fseg_free_page_low( { ut_ad(!memcmp(FSEG_MAGIC_N_BYTES, FSEG_MAGIC_N + seg_inode, 4)); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); - ut_ad(iblock->page.frame == page_align(seg_inode)); + ut_ad(iblock->page.is_physical_address(seg_inode)); ut_d(space->modify_check(*mtr)); #ifdef BTR_CUR_HASH_ADAPT @@ -2566,9 +2579,7 @@ fseg_free_page_low( } compile_time_assert(FIL_NULL == 0xffffffff); - mtr->memset(iblock, uint16_t(seg_inode - - iblock->page.frame) - + FSEG_FRAG_ARR + mtr->memset(iblock, seg_inode + FSEG_FRAG_ARR + i * FSEG_FRAG_SLOT_SIZE, 4, 0xff); break; } @@ -2584,22 +2595,17 @@ fseg_free_page_low( byte* p_not_full = seg_inode + FSEG_NOT_FULL_N_USED; uint32_t not_full_n_used = mach_read_from_4(p_not_full); - const uint16_t xoffset= uint16_t(descr - xdes->page.frame - + XDES_FLST_NODE); - const uint16_t ioffset= uint16_t(seg_inode - iblock->page.frame); const uint32_t limit = space->free_limit; if (xdes_is_full(descr)) { /* The fragment is full: move it to another list */ - err = flst_remove(iblock, - static_cast(FSEG_FULL + ioffset), - xdes, xoffset, limit, mtr); + err = flst_remove(iblock, seg_inode + FSEG_FULL, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } - err = flst_add_last(iblock, static_cast(FSEG_NOT_FULL - + ioffset), - xdes, xoffset, limit, mtr); + err = flst_add_last(iblock, seg_inode + FSEG_NOT_FULL, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } @@ -2615,9 +2621,8 @@ fseg_free_page_low( xdes_set_free(*xdes, descr, offset & (extent_size - 1), mtr); if (!xdes_get_n_used(descr)) { - err = flst_remove(iblock, static_cast(FSEG_NOT_FULL - + ioffset), - xdes, xoffset, limit, mtr); + err = flst_remove(iblock, seg_inode + FSEG_NOT_FULL, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } @@ -2656,8 +2661,9 @@ dberr_t fseg_free_page(fseg_header_t *seg_header, fil_space_t *space, mtr, &iblock, &err)) { if (!space->full_crc32()) - fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr); - return fseg_free_page_low(seg_inode, iblock, space, offset, mtr); + fil_block_check_type(*iblock, page_align(seg_inode), + FIL_PAGE_INODE, mtr); + return fseg_free_page_low(iblock, seg_inode, space, offset, mtr); } return err; @@ -2686,15 +2692,15 @@ dberr_t fseg_page_is_allocated(fil_space_t *space, unsigned page) RW_S_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, &mtr, &err)) { + const page_t *frame= b->page.frame; if (!dpage && (space->free_limit != - mach_read_from_4(FSP_FREE_LIMIT + FSP_HEADER_OFFSET + - b->page.frame) || + mach_read_from_4(FSP_FREE_LIMIT + FSP_HEADER_OFFSET + frame) || space->size_in_header != - mach_read_from_4(FSP_SIZE + FSP_HEADER_OFFSET + b->page.frame))) + mach_read_from_4(FSP_SIZE + FSP_HEADER_OFFSET + frame))) err= DB_CORRUPTION; else - err= xdes_is_free(b->page.frame + XDES_ARR_OFFSET + XDES_SIZE + err= xdes_is_free(frame + XDES_ARR_OFFSET + XDES_SIZE * xdes_calc_descriptor_index(zip_size, page), page & (FSP_EXTENT_SIZE - 1)) ? DB_SUCCESS @@ -2742,10 +2748,6 @@ fseg_free_extent( ut_d(space->modify_check(*mtr)); const uint32_t first_page_in_extent = page - (page % FSP_EXTENT_SIZE); - const uint16_t xoffset= uint16_t(descr - xdes->page.frame - + XDES_FLST_NODE); - const uint16_t ioffset= uint16_t(seg_inode - iblock->page.frame); - #ifdef BTR_CUR_HASH_ADAPT if (ahi) { for (uint32_t i = 0; i < FSP_EXTENT_SIZE; i++) { @@ -2761,23 +2763,24 @@ fseg_free_extent( } #endif /* BTR_CUR_HASH_ADAPT */ - uint16_t lst; + byte* lst = seg_inode; uint32_t limit = space->free_limit; if (xdes_is_full(descr)) { - lst = static_cast(FSEG_FULL + ioffset); + lst += FSEG_FULL; remove: - err = flst_remove(iblock, lst, xdes, xoffset, limit, mtr); + err = flst_remove(iblock, lst, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } } else if (!xdes_get_n_used(descr)) { - lst = static_cast(FSEG_FREE + ioffset); - goto remove; + lst += FSEG_FREE; + goto remove; } else { - err = flst_remove( - iblock, static_cast(FSEG_NOT_FULL + ioffset), - xdes, xoffset, limit, mtr); + lst += FSEG_NOT_FULL; + err = flst_remove(iblock, lst, + xdes, descr + XDES_FLST_NODE, limit, mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { return err; } @@ -2862,7 +2865,8 @@ fseg_free_step( } if (!space->full_crc32()) { - fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr); + fil_block_check_type(*iblock, page_align(inode), + FIL_PAGE_INODE, mtr); } dberr_t err; @@ -2893,7 +2897,7 @@ fseg_free_step( page_no_t page_no = fseg_get_nth_frag_page_no(inode, n); - if (fseg_free_page_low(inode, iblock, space, page_no, mtr + if (fseg_free_page_low(iblock, inode, space, page_no, mtr #ifdef BTR_CUR_HASH_ADAPT , ahi #endif /* BTR_CUR_HASH_ADAPT */ @@ -2926,7 +2930,8 @@ fseg_free_step_not_header( { fseg_inode_t* inode; - const uint32_t space_id = page_get_space_id(page_align(header)); + page_t* const page = page_align(header); + const uint32_t space_id = page_get_space_id(page); ut_ad(mtr->is_named_space(space_id)); fil_space_t* space = mtr->x_lock_space(space_id); @@ -2941,12 +2946,13 @@ fseg_free_step_not_header( if (!inode) { ib::warn() << "Double free of " << page_id_t(space_id, - page_get_page_no(page_align(header))); + page_get_page_no(page)); return true; } if (!space->full_crc32()) { - fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr); + fil_block_check_type(*iblock, page_align(inode), + FIL_PAGE_INODE, mtr); } dberr_t err; @@ -2973,11 +2979,11 @@ fseg_free_step_not_header( uint32_t page_no = fseg_get_nth_frag_page_no(inode, n); - if (page_no == page_get_page_no(page_align(header))) { + if (page_no == page_get_page_no(page)) { return true; } - if (fseg_free_page_low(inode, iblock, space, page_no, mtr + if (fseg_free_page_low(iblock, inode, space, page_no, mtr #ifdef BTR_CUR_HASH_ADAPT , ahi #endif /* BTR_CUR_HASH_ADAPT */ diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 90322ce167ea0..2787d29cdcc5d 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -3453,18 +3453,17 @@ fts_add_doc_by_id( BTR_SEARCH_LEAF, &pcur, &mtr) == DB_SUCCESS && btr_pcur_get_low_match(&pcur) == n_uniq) { - const rec_t* rec; btr_pcur_t* doc_pcur; const rec_t* clust_rec; btr_pcur_t clust_pcur; rec_offs* offsets = NULL; ulint num_idx = ib_vector_size(cache->get_docs); - - rec = btr_pcur_get_rec(&pcur); + const rec_t* rec = btr_pcur_get_rec(&pcur); + const page_t* page = btr_pcur_get_page(&pcur); /* Doc could be deleted */ - if (page_rec_is_infimum(rec) - || rec_get_deleted_flag(rec, dict_table_is_comp(table))) { + if (page_rec_is_infimum(page, rec) + || rec_get_deleted_flag(rec, page_is_comp(page))) { goto func_exit; } @@ -3660,7 +3659,8 @@ fts_get_max_doc_id( do { rec = btr_pcur_get_rec(&pcur); - if (!page_rec_is_user_rec(rec)) { + if (!page_rec_is_user_rec(btr_pcur_get_page(&pcur), + rec)) { continue; } diff --git a/storage/innobase/fut/fut0lst.cc b/storage/innobase/fut/fut0lst.cc index 48e2fbe38aad5..003590bbe8747 100644 --- a/storage/innobase/fut/fut0lst.cc +++ b/storage/innobase/fut/fut0lst.cc @@ -73,35 +73,33 @@ static void flst_write_addr(const buf_block_t& block, byte *faddr, static void flst_zero_both(const buf_block_t& b, byte *addr, mtr_t *mtr) { if (mach_read_from_4(addr + FIL_ADDR_PAGE) != FIL_NULL) - mtr->memset(&b, ulint(addr - b.page.frame) + FIL_ADDR_PAGE, 4, 0xff); + mtr->memset(&b, addr + FIL_ADDR_PAGE, 4, 0xff); mtr->write<2,mtr_t::MAYBE_NOP>(b, addr + FIL_ADDR_BYTE, 0U); /* Initialize the other address by (MEMMOVE|0x80,offset,FIL_ADDR_SIZE,source) which is 4 bytes, or less than FIL_ADDR_SIZE. */ memcpy(addr + FIL_ADDR_SIZE, addr, FIL_ADDR_SIZE); - const uint16_t boffset= page_offset(addr); - mtr->memmove(b, boffset + FIL_ADDR_SIZE, boffset, FIL_ADDR_SIZE); + mtr->memmove(b, addr + FIL_ADDR_SIZE, addr, FIL_ADDR_SIZE); } /** Add a node to an empty list. */ -static void flst_add_to_empty(buf_block_t *base, uint16_t boffset, - buf_block_t *add, uint16_t aoffset, mtr_t *mtr) +static void flst_add_to_empty(buf_block_t *base, byte *boffset, + buf_block_t *add, byte *aoffset, mtr_t *mtr) { ut_ad(base != add || boffset != aoffset); - ut_ad(boffset < base->physical_size()); - ut_ad(aoffset < add->physical_size()); + ut_ad(base->page.is_physical_address(boffset)); + ut_ad(add->page.is_physical_address(aoffset)); ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - ut_ad(!mach_read_from_4(base->page.frame + boffset + FLST_LEN)); - mtr->write<1>(*base, base->page.frame + boffset + (FLST_LEN + 3), 1U); + ut_ad(!mach_read_from_4(boffset + FLST_LEN)); + mtr->write<1>(*base, boffset + (FLST_LEN + 3), 1U); /* Update first and last fields of base node */ - flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST, - add->page.id().page_no(), aoffset, mtr); - memcpy(base->page.frame + boffset + FLST_LAST, - base->page.frame + boffset + FLST_FIRST, - FIL_ADDR_SIZE); + flst_write_addr(*base, boffset + FLST_FIRST, + add->page.id().page_no(), + uint16_t(aoffset - add->page.frame), mtr); + memcpy(boffset + FLST_LAST, boffset + FLST_FIRST, FIL_ADDR_SIZE); /* Initialize FLST_LAST by (MEMMOVE|0x80,offset,FIL_ADDR_SIZE,source) which is 4 bytes, or less than FIL_ADDR_SIZE. */ mtr->memmove(*base, boffset + FLST_LAST, boffset + FLST_FIRST, @@ -109,7 +107,7 @@ static void flst_add_to_empty(buf_block_t *base, uint16_t boffset, /* Set prev and next fields of node to add */ static_assert(FLST_NEXT == FLST_PREV + FIL_ADDR_SIZE, "compatibility"); - flst_zero_both(*add, add->page.frame + aoffset + FLST_PREV, mtr); + flst_zero_both(*add, aoffset + FLST_PREV, mtr); } /** Insert a node after another one. @@ -121,17 +119,17 @@ static void flst_add_to_empty(buf_block_t *base, uint16_t boffset, @param aoffset byte offset of the block to be added @param limit fil_space_t::free_limit @param mtr mini-transaction */ -static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset, - buf_block_t *cur, uint16_t coffset, - buf_block_t *add, uint16_t aoffset, +static dberr_t flst_insert_after(buf_block_t *base, byte *boffset, + buf_block_t *cur, byte *coffset, + buf_block_t *add, byte *aoffset, uint32_t limit, mtr_t *mtr) { - ut_ad(base != cur || boffset != coffset); - ut_ad(base != add || boffset != aoffset); - ut_ad(cur != add || coffset != aoffset); - ut_ad(boffset < base->physical_size()); - ut_ad(coffset < cur->physical_size()); - ut_ad(aoffset < add->physical_size()); + ut_ad(boffset != coffset); + ut_ad(boffset != aoffset); + ut_ad(coffset != aoffset); + ut_ad(base->page.is_physical_address(boffset)); + ut_ad(cur->page.is_physical_address(coffset)); + ut_ad(add->page.is_physical_address(aoffset)); ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->memo_contains_flagged(cur, MTR_MEMO_PAGE_X_FIX | @@ -139,7 +137,7 @@ static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset, ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - fil_addr_t next_addr= flst_get_next_addr(cur->page.frame + coffset); + fil_addr_t next_addr= flst_get_next_addr(coffset); if (next_addr.page >= limit) { if (UNIV_UNLIKELY(next_addr.page != FIL_NULL)) @@ -150,28 +148,30 @@ static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset, FIL_PAGE_DATA_END)) return DB_CORRUPTION; - flst_write_addr(*add, add->page.frame + aoffset + FLST_PREV, - cur->page.id().page_no(), coffset, mtr); - flst_write_addr(*add, add->page.frame + aoffset + FLST_NEXT, + flst_write_addr(*add, aoffset + FLST_PREV, + cur->page.id().page_no(), + uint16_t(coffset - cur->page.frame), mtr); + flst_write_addr(*add, aoffset + FLST_NEXT, next_addr.page, next_addr.boffset, mtr); dberr_t err= DB_SUCCESS; + const uint16_t a= uint16_t(aoffset - add->page.frame); + if (next_addr.page == FIL_NULL) - flst_write_addr(*base, base->page.frame + boffset + FLST_LAST, - add->page.id().page_no(), aoffset, mtr); + flst_write_addr(*base, boffset + FLST_LAST, + add->page.id().page_no(), a, mtr); else if (buf_block_t *block= buf_page_get_gen(page_id_t{add->page.id().space(), next_addr.page}, add->zip_size(), RW_SX_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, mtr, &err)) flst_write_addr(*block, block->page.frame + next_addr.boffset + FLST_PREV, - add->page.id().page_no(), aoffset, mtr); + add->page.id().page_no(), a, mtr); - flst_write_addr(*cur, cur->page.frame + coffset + FLST_NEXT, - add->page.id().page_no(), aoffset, mtr); + flst_write_addr(*cur, coffset + FLST_NEXT, add->page.id().page_no(), a, mtr); - byte *len= &base->page.frame[boffset + FLST_LEN]; + byte *len= &boffset[FLST_LEN]; mtr->write<4>(*base, len, mach_read_from_4(len) + 1); return err; } @@ -186,17 +186,17 @@ static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset, @param limit fil_space_t::free_limit @param mtr mini-transaction @return error code */ -static dberr_t flst_insert_before(buf_block_t *base, uint16_t boffset, - buf_block_t *cur, uint16_t coffset, - buf_block_t *add, uint16_t aoffset, +static dberr_t flst_insert_before(buf_block_t *base, byte *boffset, + buf_block_t *cur, byte *coffset, + buf_block_t *add, byte *aoffset, uint32_t limit, mtr_t *mtr) { - ut_ad(base != cur || boffset != coffset); - ut_ad(base != add || boffset != aoffset); - ut_ad(cur != add || coffset != aoffset); - ut_ad(boffset < base->physical_size()); - ut_ad(coffset < cur->physical_size()); - ut_ad(aoffset < add->physical_size()); + ut_ad(boffset != coffset); + ut_ad(boffset != aoffset); + ut_ad(coffset != aoffset); + ut_ad(base->page.is_physical_address(boffset)); + ut_ad(cur->page.is_physical_address(coffset)); + ut_ad(add->page.is_physical_address(aoffset)); ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->memo_contains_flagged(cur, MTR_MEMO_PAGE_X_FIX | @@ -204,7 +204,7 @@ static dberr_t flst_insert_before(buf_block_t *base, uint16_t boffset, ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - fil_addr_t prev_addr= flst_get_prev_addr(cur->page.frame + coffset); + fil_addr_t prev_addr= flst_get_prev_addr(coffset); if (prev_addr.page >= limit) { if (UNIV_UNLIKELY(prev_addr.page != FIL_NULL)) @@ -215,28 +215,29 @@ static dberr_t flst_insert_before(buf_block_t *base, uint16_t boffset, FIL_PAGE_DATA_END)) return DB_CORRUPTION; - flst_write_addr(*add, add->page.frame + aoffset + FLST_PREV, + flst_write_addr(*add, aoffset + FLST_PREV, prev_addr.page, prev_addr.boffset, mtr); - flst_write_addr(*add, add->page.frame + aoffset + FLST_NEXT, - cur->page.id().page_no(), coffset, mtr); + flst_write_addr(*add, aoffset + FLST_NEXT, + cur->page.id().page_no(), + uint16_t(coffset - cur->page.frame), mtr); dberr_t err= DB_SUCCESS; + const uint16_t a= uint16_t(aoffset - add->page.frame); if (prev_addr.page == FIL_NULL) - flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST, - add->page.id().page_no(), aoffset, mtr); + flst_write_addr(*base, boffset + FLST_FIRST, + add->page.id().page_no(), a, mtr); else if (buf_block_t *block= buf_page_get_gen(page_id_t{add->page.id().space(), prev_addr.page}, add->zip_size(), RW_SX_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, mtr, &err)) flst_write_addr(*block, block->page.frame + prev_addr.boffset + FLST_NEXT, - add->page.id().page_no(), aoffset, mtr); + add->page.id().page_no(), a, mtr); - flst_write_addr(*cur, cur->page.frame + coffset + FLST_PREV, - add->page.id().page_no(), aoffset, mtr); + flst_write_addr(*cur, coffset + FLST_PREV, add->page.id().page_no(), a, mtr); - byte *len= &base->page.frame[boffset + FLST_LEN]; + byte *len= &boffset[FLST_LEN]; mtr->write<4>(*base, len, mach_read_from_4(len) + 1); return err; } @@ -254,25 +255,25 @@ void flst_init(const buf_block_t& block, byte *base, mtr_t *mtr) flst_zero_both(block, base + FLST_FIRST, mtr); } -dberr_t flst_add_last(buf_block_t *base, uint16_t boffset, - buf_block_t *add, uint16_t aoffset, +dberr_t flst_add_last(buf_block_t *base, byte *boffset, + buf_block_t *add, byte *aoffset, uint32_t limit, mtr_t *mtr) { - ut_ad(base != add || boffset != aoffset); - ut_ad(boffset < base->physical_size()); - ut_ad(aoffset < add->physical_size()); + ut_ad(boffset != aoffset); + ut_ad(base->page.is_physical_address(boffset)); + ut_ad(add->page.is_physical_address(aoffset)); ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - if (!flst_get_len(base->page.frame + boffset)) + if (!flst_get_len(boffset)) { flst_add_to_empty(base, boffset, add, aoffset, mtr); return DB_SUCCESS; } else { - fil_addr_t addr= flst_get_last(base->page.frame + boffset); + fil_addr_t addr= flst_get_last(boffset); if (UNIV_UNLIKELY(addr.page >= limit)) return DB_CORRUPTION; else if (UNIV_UNLIKELY(addr.boffset < FIL_PAGE_DATA || @@ -287,31 +288,32 @@ dberr_t flst_add_last(buf_block_t *base, uint16_t boffset, add->zip_size(), RW_SX_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, mtr, &err))) return err; - return flst_insert_after(base, boffset, cur, addr.boffset, + return flst_insert_after(base, boffset, cur, + cur->page.frame + addr.boffset, add, aoffset, limit, mtr); } } -dberr_t flst_add_first(buf_block_t *base, uint16_t boffset, - buf_block_t *add, uint16_t aoffset, +dberr_t flst_add_first(buf_block_t *base, byte *boffset, + buf_block_t *add, byte *aoffset, uint32_t limit, mtr_t *mtr) { ut_ad(base != add || boffset != aoffset); - ut_ad(boffset < base->physical_size()); - ut_ad(aoffset < add->physical_size()); + ut_ad(base->page.is_physical_address(boffset)); + ut_ad(add->page.is_physical_address(aoffset)); ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - if (!flst_get_len(base->page.frame + boffset)) + if (!flst_get_len(boffset)) { flst_add_to_empty(base, boffset, add, aoffset, mtr); return DB_SUCCESS; } else { - fil_addr_t addr= flst_get_first(base->page.frame + boffset); + fil_addr_t addr= flst_get_first(boffset); if (UNIV_UNLIKELY(addr.page >= limit)) return DB_CORRUPTION; else if (UNIV_UNLIKELY(addr.boffset < FIL_PAGE_DATA || @@ -325,24 +327,25 @@ dberr_t flst_add_first(buf_block_t *base, uint16_t boffset, add->zip_size(), RW_SX_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, mtr, &err))) return err; - return flst_insert_before(base, boffset, cur, addr.boffset, + return flst_insert_before(base, boffset, cur, + cur->page.frame + addr.boffset, add, aoffset, limit, mtr); } } -dberr_t flst_remove(buf_block_t *base, uint16_t boffset, - buf_block_t *cur, uint16_t coffset, +dberr_t flst_remove(buf_block_t *base, byte *boffset, + buf_block_t *cur, byte *coffset, uint32_t limit, mtr_t *mtr) { - ut_ad(boffset < base->physical_size()); - ut_ad(coffset < cur->physical_size()); + ut_ad(base->page.is_physical_address(boffset)); + ut_ad(cur->page.is_physical_address(coffset)); ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); ut_ad(mtr->memo_contains_flagged(cur, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - const fil_addr_t prev_addr= flst_get_prev_addr(cur->page.frame + coffset); - const fil_addr_t next_addr= flst_get_next_addr(cur->page.frame + coffset); + const fil_addr_t prev_addr= flst_get_prev_addr(coffset); + const fil_addr_t next_addr= flst_get_next_addr(coffset); dberr_t err= DB_SUCCESS; if (next_addr.page >= limit) @@ -359,7 +362,7 @@ dberr_t flst_remove(buf_block_t *base, uint16_t boffset, { if (prev_addr.page != FIL_NULL) return DB_CORRUPTION; - flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST, + flst_write_addr(*base, boffset + FLST_FIRST, next_addr.page, next_addr.boffset, mtr); } else if (UNIV_UNLIKELY(prev_addr.boffset < FIL_PAGE_DATA || @@ -368,33 +371,52 @@ dberr_t flst_remove(buf_block_t *base, uint16_t boffset, return DB_CORRUPTION; else { - buf_block_t *b= cur; - if (prev_addr.page == b->page.id().page_no() || - (b= buf_page_get_gen(page_id_t(b->page.id().space(), prev_addr.page), - b->zip_size(), RW_SX_LATCH, nullptr, - BUF_GET_POSSIBLY_FREED, mtr, &err))) + do + { + buf_block_t *b= cur; + if (prev_addr.page != b->page.id().page_no()) + { + b= buf_page_get_gen(page_id_t(b->page.id().space(), prev_addr.page), + b->zip_size(), RW_SX_LATCH, nullptr, + BUF_GET_POSSIBLY_FREED, mtr, &err); + if (UNIV_UNLIKELY(!b)) + continue; + } flst_write_addr(*b, b->page.frame + prev_addr.boffset + FLST_NEXT, next_addr.page, next_addr.boffset, mtr); + } + while (0); } if (next_addr.page == FIL_NULL) - flst_write_addr(*base, base->page.frame + boffset + FLST_LAST, + flst_write_addr(*base, boffset + FLST_LAST, prev_addr.page, prev_addr.boffset, mtr); else { - dberr_t err2; - if (next_addr.page == cur->page.id().page_no() || - (cur= buf_page_get_gen(page_id_t(cur->page.id().space(), - next_addr.page), - cur->zip_size(), RW_SX_LATCH, nullptr, - BUF_GET_POSSIBLY_FREED, mtr, &err2))) + do + { + if (next_addr.page != cur->page.id().page_no()) + { + dberr_t err2; + cur= buf_page_get_gen(page_id_t(cur->page.id().space(), + next_addr.page), + cur->zip_size(), RW_SX_LATCH, nullptr, + BUF_GET_POSSIBLY_FREED, mtr, &err2); + if (!cur) + { + if (err == DB_SUCCESS) + err= err2; + continue; + } + } + flst_write_addr(*cur, cur->page.frame + next_addr.boffset + FLST_PREV, prev_addr.page, prev_addr.boffset, mtr); - else if (err == DB_SUCCESS) - err= err2; + } + while (0); } - byte *len= &base->page.frame[boffset + FLST_LEN]; + byte *len= &boffset[FLST_LEN]; if (UNIV_UNLIKELY(!mach_read_from_4(len))) return DB_CORRUPTION; mtr->write<4>(*base, len, mach_read_from_4(len) - 1); @@ -409,8 +431,9 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr) ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - const uint32_t len= flst_get_len(base->page.frame + boffset); - fil_addr_t addr= flst_get_first(base->page.frame + boffset); + const byte *const flst= base->page.frame + boffset; + const uint32_t len= flst_get_len(flst); + fil_addr_t addr= flst_get_first(flst); for (uint32_t i= len; i--; ) { @@ -426,7 +449,7 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr) ut_ad(addr.page == FIL_NULL); - addr= flst_get_last(base->page.frame + boffset); + addr= flst_get_last(flst); for (uint32_t i= len; i--; ) { diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index 83afd732b2161..b63db3f6214b4 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -62,14 +62,12 @@ rtr_page_split_initialize_nodes( rtr_split_node_t* stop; rtr_split_node_t* cur; rec_t* rec; - buf_block_t* block; page_t* page; ulint n_uniq; ulint len; const byte* source_cur; - block = btr_cur_get_block(cursor); - page = buf_block_get_frame(block); + page = btr_cur_get_page(cursor); n_uniq = dict_index_get_n_unique_in_tree(cursor->index()); n_recs = ulint(page_get_n_recs(page)) + 1; @@ -86,7 +84,7 @@ rtr_page_split_initialize_nodes( *buf_pos = buf; stop = task + n_recs; - rec = page_rec_get_next(page_get_infimum_rec(page)); + rec = page_rec_get_first(page); const ulint n_core = page_is_leaf(page) ? cursor->index()->n_core_fields : 0; *offsets = rec_get_offsets(rec, cursor->index(), *offsets, n_core, @@ -100,7 +98,7 @@ rtr_page_split_initialize_nodes( memcpy(cur->coords, source_cur, DATA_MBR_LEN); - rec = page_rec_get_next(rec); + rec = page_rec_get_next(page, rec); *offsets = rec_get_offsets(rec, cursor->index(), *offsets, n_core, n_uniq, &heap); source_cur = rec_get_nth_field(rec, *offsets, 0, &len); @@ -202,8 +200,6 @@ rtr_update_mbr_field( { dict_index_t* index = cursor->index(); mem_heap_t* heap; - page_t* page; - rec_t* rec; constexpr ulint flags = BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG; @@ -220,14 +216,13 @@ rtr_update_mbr_field( ulint del_page_no = 0; rec_offs* offsets2; - rec = btr_cur_get_rec(cursor); - page = page_align(rec); + rec_t* rec = btr_cur_get_rec(cursor); + page_t *const page = btr_cur_get_page(cursor); rec_info = rec_get_info_bits(rec, rec_offs_comp(offsets)); heap = mem_heap_create(100); block = btr_cur_get_block(cursor); - ut_ad(page == buf_block_get_frame(block)); child = btr_node_ptr_get_child_page_no(rec, offsets); const ulint n_core = page_is_leaf(block->page.frame) @@ -236,7 +231,7 @@ rtr_update_mbr_field( if (new_rec) { child_rec = new_rec; } else { - child_rec = page_rec_get_next(page_get_infimum_rec(child_page)); + child_rec = page_rec_get_first(child_page); } dtuple_t* node_ptr = rtr_index_build_node_ptr( @@ -251,7 +246,8 @@ rtr_update_mbr_field( index, NULL, 0, ULINT_UNDEFINED, &heap); del_page_no = btr_node_ptr_get_child_page_no(del_rec, offsets2); - cur2_pos = page_rec_get_n_recs_before(btr_cur_get_rec(cursor2)); + cur2_pos = page_rec_get_n_recs_before( + btr_cur_get_page(cursor2), del_rec); } ut_ad(rec_offs_validate(rec, index, offsets)); @@ -337,7 +333,7 @@ rtr_update_mbr_field( ut_ad(cursor2 == NULL); /* Insert the new mbr rec. */ - old_pos = page_rec_get_n_recs_before(rec); + old_pos = page_rec_get_n_recs_before(page, rec); err = btr_cur_optimistic_insert( flags, @@ -367,7 +363,7 @@ rtr_update_mbr_field( rec_t* next_rec; /* Delete the rec which cursor point to. */ - next_rec = page_rec_get_next(rec); + next_rec = page_rec_get_next(page, rec); page_cur_delete_rec(&cursor->page_cur, offsets, mtr); if (!ins_suc) { ut_ad(rec_info & REC_INFO_MIN_REC_FLAG); @@ -393,7 +389,8 @@ rtr_update_mbr_field( pointer on a non-leaf level, we must mark the new leftmost node pointer as the predefined minimum record */ - rec_t* next_rec = page_rec_get_next(cur2_rec); + rec_t* next_rec = page_rec_get_next( + block->page.frame, cur2_rec); btr_set_min_rec_mark(next_rec, *block, mtr); } @@ -469,8 +466,8 @@ rtr_update_mbr_field( cur2_rec = page_get_infimum_rec(page); while ((cur2_rec - = page_rec_get_next(cur2_rec))) { - if (page_rec_is_supremum(cur2_rec)) { + = page_rec_get_next(page, cur2_rec))) { + if (page_rec_is_supremum(page, cur2_rec)) { break; } @@ -498,7 +495,8 @@ rtr_update_mbr_field( pointer on a non-leaf level, we must mark the new leftmost node pointer as the predefined minimum record */ - rec_t* next_rec = page_rec_get_next(cur2_rec); + rec_t* next_rec + = page_rec_get_next(page, cur2_rec); btr_set_min_rec_mark(next_rec, *block, mtr); } @@ -532,7 +530,7 @@ rtr_update_mbr_field( ut_ad(page_has_prev(page) || (REC_INFO_MIN_REC_FLAG & rec_get_info_bits( - page_rec_get_next(page_get_infimum_rec(page)), + page_rec_get_first(page), page_is_comp(page)))); err_exit: mem_heap_free(heap); @@ -574,9 +572,12 @@ rtr_adjust_upper_level( cursor.page_cur.index = sea_cur->index(); cursor.page_cur.block = block; + page_t* page = block->page.frame; + page_t* new_page = new_block->page.frame; + /* Get the level of the split pages */ - level = btr_page_get_level(buf_block_get_frame(block)); - ut_ad(level == btr_page_get_level(buf_block_get_frame(new_block))); + level = btr_page_get_level(page); + ut_ad(level == btr_page_get_level(new_page)); page_no = block->page.id().page_no(); @@ -588,7 +589,7 @@ rtr_adjust_upper_level( page_cursor = btr_cur_get_page_cur(&cursor); - rtr_update_mbr_field(&cursor, offsets, nullptr, block->page.frame, mbr, + rtr_update_mbr_field(&cursor, offsets, nullptr, page, mbr, nullptr, mtr); /* Already updated parent MBR, reset in our path */ @@ -602,8 +603,7 @@ rtr_adjust_upper_level( dberr_t err; - if (const rec_t* first = page_rec_get_next_const( - page_get_infimum_rec(new_block->page.frame))) { + if (const rec_t* first = page_rec_get_first(new_page)) { /* Insert the node for the new page. */ node_ptr_upper = rtr_index_build_node_ptr( sea_cur->index(), new_mbr, first, new_page_no, heap); @@ -664,27 +664,27 @@ rtr_adjust_upper_level( return err; } - const uint32_t next_page_no = btr_page_get_next(block->page.frame); + const uint32_t next_page_no = btr_page_get_next(page); if (next_page_no == FIL_NULL) { } else if (buf_block_t* next_block = btr_block_get(*sea_cur->index(), next_page_no, RW_X_LATCH, false, mtr, &err)) { - if (UNIV_UNLIKELY(memcmp_aligned<4>(next_block->page.frame - + FIL_PAGE_PREV, - block->page.frame + page_t *next_page = next_block->page.frame; + if (UNIV_UNLIKELY(memcmp_aligned<4>(next_page + FIL_PAGE_PREV, + page + FIL_PAGE_OFFSET, 4))) { return DB_CORRUPTION; } - btr_page_set_prev(next_block, new_page_no, mtr); + btr_page_set_prev(next_block, next_page, new_page_no, mtr); } else { return err; } - btr_page_set_next(block, new_page_no, mtr); + btr_page_set_next(block, page, new_page_no, mtr); - btr_page_set_prev(new_block, page_no, mtr); - btr_page_set_next(new_block, next_page_no, mtr); + btr_page_set_prev(new_block, new_page, page_no, mtr); + btr_page_set_next(new_block, new_page, next_page_no, mtr); return DB_SUCCESS; } @@ -740,8 +740,8 @@ rtr_split_page_move_rec_list( page_cur_set_before_first(new_block, &new_page_cursor); page_cursor.index = new_page_cursor.index = index; - page = buf_block_get_frame(block); - new_page = buf_block_get_frame(new_block); + page = page_cur_get_page(&page_cursor); + new_page = page_cur_get_page(&new_page_cursor); end_split_node = node_array + page_get_n_recs(page); @@ -751,7 +751,7 @@ rtr_split_page_move_rec_list( log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); } - max_to_move = page_get_n_recs(buf_block_get_frame(block)); + max_to_move = page_get_n_recs(page); rec_move = static_cast(mem_heap_alloc( heap, sizeof (*rec_move) * max_to_move)); @@ -909,7 +909,7 @@ rtr_page_split_and_insert( ut_ad(cursor->index()->lock.have_u_or_x()); block = btr_cur_get_block(cursor); - page = buf_block_get_frame(block); + page = btr_cur_get_page(cursor); page_zip = buf_block_get_page_zip(block); current_ssn = page_get_ssn_id(page); @@ -919,8 +919,7 @@ rtr_page_split_and_insert( const page_id_t page_id(block->page.id()); if (!page_has_prev(page) && !page_is_leaf(page)) { - first_rec = page_rec_get_next( - page_get_infimum_rec(buf_block_get_frame(block))); + first_rec = page_rec_get_first(page); if (UNIV_UNLIKELY(!first_rec)) { corrupted: *err = DB_CORRUPTION; @@ -966,16 +965,16 @@ rtr_page_split_and_insert( return nullptr; } + new_page = new_block->page.frame; new_page_zip = buf_block_get_page_zip(new_block); if (page_level && UNIV_LIKELY_NULL(new_page_zip)) { /* ROW_FORMAT=COMPRESSED non-leaf pages are not expected to contain FIL_NULL in FIL_PAGE_PREV at this stage. */ - memset_aligned<4>(new_block->page.frame + FIL_PAGE_PREV, 0, 4); + memset_aligned<4>(new_page + FIL_PAGE_PREV, 0, 4); } btr_page_create(new_block, new_page_zip, cursor->index(), page_level, mtr); - new_page = buf_block_get_frame(new_block); ut_ad(page_get_ssn_id(new_page) == 0); /* Set new ssn to the new page and page. */ @@ -1031,6 +1030,7 @@ rtr_page_split_and_insert( cur_split_node < end_split_node - 1; ++cur_split_node) { if (cur_split_node->n_node != first_rec_group) { pos = page_rec_get_n_recs_before( + page_align(cur_split_node->key), cur_split_node->key); rec = page_rec_get_nth(new_page, pos); ut_a(rec); @@ -1060,12 +1060,14 @@ rtr_page_split_and_insert( ulint pos; pos = page_rec_get_n_recs_before( - cur_split_node->key); + page_align(cur_split_node->key), + cur_split_node->key); ut_a(pos > 0); rec_t* new_rec = page_rec_get_nth(new_page, pos - n); - ut_a(new_rec && page_rec_is_user_rec(new_rec)); + ut_a(new_rec); + ut_a(page_rec_is_user_rec(new_page, new_rec)); page_cur_position(new_rec, new_block, page_cursor); @@ -1193,19 +1195,16 @@ rtr_page_split_and_insert( cursor->rtr_info = NULL; IF_DBUG(iterated=true,); - rec_t* i_rec = page_rec_get_next(page_get_infimum_rec( - buf_block_get_frame(block))); - if (UNIV_UNLIKELY(!i_rec)) { + page_cur_set_before_first(block, &cursor->page_cur); + if (!page_cur_move_to_next(&cursor->page_cur)) { goto corrupted; } - btr_cur_position(cursor->index(), i_rec, block, cursor); - goto func_start; } #ifdef UNIV_GIS_DEBUG - ut_ad(page_validate(buf_block_get_frame(block), cursor->index())); - ut_ad(page_validate(buf_block_get_frame(new_block), cursor->index())); + ut_ad(page_validate(page, cursor->index())); + ut_ad(page_validate(new_page, cursor->index())); ut_ad(!rec || rec_offs_validate(rec, cursor->index(), *offsets)); #endif @@ -1267,7 +1266,7 @@ rtr_ins_enlarge_mbr( offsets = rtr_page_get_father_block( NULL, heap, mtr, btr_cur, &cursor); - page = buf_block_get_frame(block); + page = block->page.frame; /* Update the mbr field of the rec. */ rtr_update_mbr_field(&cursor, offsets, NULL, page, @@ -1297,7 +1296,7 @@ rtr_page_copy_rec_list_end_no_locks( ulint* num_moved, /*!< out: num of rec to move */ mtr_t* mtr) /*!< in: mtr */ { - page_t* new_page = buf_block_get_frame(new_block); + page_t* new_page = new_block->page.frame; page_cur_t page_cur; page_cur_t cur1; rec_t* cur_rec; @@ -1322,21 +1321,20 @@ rtr_page_copy_rec_list_end_no_locks( ut_a(mach_read_from_2(new_page + srv_page_size - 10) == (ulint) (page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM)); - cur_rec = page_rec_get_next( - page_get_infimum_rec(buf_block_get_frame(new_block))); - if (UNIV_UNLIKELY(!cur_rec)) { + page_cur_set_before_first(new_block, &page_cur); + if (UNIV_UNLIKELY(!page_cur_move_to_next(&page_cur))) { return DB_CORRUPTION; } - page_cur_position(cur_rec, new_block, &page_cur); page_cur.index = index; + cur_rec = page_cur_get_rec(&page_cur); /* Copy records from the original page to the new page */ while (!page_cur_is_after_last(&cur1)) { rec_t* cur1_rec = page_cur_get_rec(&cur1); rec_t* ins_rec; - if (page_rec_is_infimum(cur_rec)) { - cur_rec = page_rec_get_next(cur_rec); + if (page_rec_is_infimum(new_page, cur_rec)) { + cur_rec = page_rec_get_next(new_page, cur_rec); if (UNIV_UNLIKELY(!cur_rec)) { return DB_CORRUPTION; } @@ -1344,7 +1342,7 @@ rtr_page_copy_rec_list_end_no_locks( offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, ULINT_UNDEFINED, &heap); - while (!page_rec_is_supremum(cur_rec)) { + while (!page_rec_is_supremum(new_page, cur_rec)) { ulint cur_matched_fields = 0; int cmp; @@ -1376,7 +1374,7 @@ rtr_page_copy_rec_list_end_no_locks( /* If position is on suprenum rec, need to move to previous rec. */ - if (page_rec_is_supremum(cur_rec)) { + if (page_rec_is_supremum(new_page, cur_rec)) { move_to_prev: cur_rec = page_cur_move_to_prev(&page_cur); } else { @@ -1428,15 +1426,12 @@ rtr_page_copy_rec_list_start_no_locks( mtr_t* mtr) /*!< in: mtr */ { page_cur_t cur1; - rec_t* cur_rec; rec_offs offsets_1[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets1 = offsets_1; rec_offs offsets_2[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets2 = offsets_2; page_cur_t page_cur; ulint moved = 0; - const ulint n_core = page_is_leaf(buf_block_get_frame(block)) - ? index->n_core_fields : 0; rec_offs_init(offsets_1); rec_offs_init(offsets_2); @@ -1446,20 +1441,25 @@ rtr_page_copy_rec_list_start_no_locks( return DB_CORRUPTION; } - cur_rec = page_rec_get_next( - page_get_infimum_rec(buf_block_get_frame(new_block))); - if (UNIV_UNLIKELY(!cur_rec)) { + const ulint n_core = page_is_leaf(page_cur_get_page(&cur1)) + ? index->n_core_fields : 0; + + page_cur_set_before_first(new_block, &page_cur); + if (UNIV_UNLIKELY(!page_cur_move_to_next(&page_cur))) { return DB_CORRUPTION; } - page_cur_position(cur_rec, new_block, &page_cur); + page_cur.index = index; + rec_t* cur_rec = page_cur_get_rec(&page_cur); + page_t* page = page_cur_get_page(&page_cur); + while (page_cur_get_rec(&cur1) != rec) { rec_t* cur1_rec = page_cur_get_rec(&cur1); rec_t* ins_rec; - if (page_rec_is_infimum(cur_rec)) { - cur_rec = page_rec_get_next(cur_rec); + if (page_rec_is_infimum(page, cur_rec)) { + cur_rec = page_rec_get_next(page, cur_rec); if (UNIV_UNLIKELY(!cur_rec)) { return DB_CORRUPTION; } @@ -1468,7 +1468,7 @@ rtr_page_copy_rec_list_start_no_locks( offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, ULINT_UNDEFINED, &heap); - while (!page_rec_is_supremum(cur_rec)) { + while (!page_rec_is_supremum(page, cur_rec)) { ulint cur_matched_fields = 0; offsets2 = rec_get_offsets(cur_rec, index, offsets2, @@ -1500,7 +1500,7 @@ rtr_page_copy_rec_list_start_no_locks( /* If position is on suprenum rec, need to move to previous rec. */ - if (page_rec_is_supremum(cur_rec)) { + if (page_rec_is_supremum(page, cur_rec)) { move_to_prev: cur_rec = page_cur_move_to_prev(&page_cur); } else { @@ -1638,9 +1638,11 @@ rtr_check_same_block( const uint32_t page_no = btr_cur_get_block(cursor)->page.id().page_no(); rec_offs* offsets; - rec_t* rec = page_get_infimum_rec(parentb->page.frame); + page_t* const page = parentb->page.frame; + rec_t* rec = page_get_infimum_rec(page); - while ((rec = page_rec_get_next(rec)) && !page_rec_is_supremum(rec)) { + while ((rec = page_rec_get_next(page, rec)) + && !page_rec_is_supremum(page, rec)) { offsets = rec_get_offsets( rec, index, NULL, 0, ULINT_UNDEFINED, &heap); @@ -1776,8 +1778,7 @@ rtr_rec_cal_increase( { const dfield_t* dtuple_field; - ut_ad(!page_rec_is_supremum(rec)); - ut_ad(!page_rec_is_infimum(rec)); + ut_ad(page_rec_is_user_rec(page_align(rec), rec)); dtuple_field = dtuple_get_nth_field(dtuple, 0); ut_ad(dfield_get_len(dtuple_field) == DATA_MBR_LEN); @@ -1848,7 +1849,7 @@ rtr_estimate_n_rows_in_range( mtr.commit(); return HA_POS_ERROR; } - const page_t* page = buf_block_get_frame(block); + const page_t* page = block->page.frame; const unsigned n_recs = page_header_get_field(page, PAGE_N_RECS); if (n_recs == 0) { @@ -1857,10 +1858,9 @@ rtr_estimate_n_rows_in_range( /* Scan records in root page and calculate area. */ double area = 0; - for (const rec_t* rec = page_rec_get_next_const( - page_get_infimum_rec(block->page.frame)); - rec && !page_rec_is_supremum(rec); - rec = page_rec_get_next_const(rec)) { + for (const rec_t* rec = page_rec_get_first(page); + rec && !page_rec_is_supremum(page, rec); + rec = page_rec_get_next(page, rec)) { rtr_mbr_t mbr; double rec_area; diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index 4aab68e9ca29d..457c62a725c95 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -101,6 +101,7 @@ rtr_latch_leaves( switch (latch_mode) { uint32_t left_page_no; uint32_t right_page_no; + const page_t* page; default: ut_ad(latch_mode == BTR_CONT_MODIFY_TREE); break; @@ -111,7 +112,8 @@ rtr_latch_leaves( MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK)); /* x-latch also siblings from left to right */ - left_page_no = btr_page_get_prev(block->page.frame); + page = block->page.frame; + left_page_no = btr_page_get_prev(page); if (left_page_no != FIL_NULL) { btr_block_get(*cursor->index(), left_page_no, RW_X_LATCH, @@ -120,7 +122,7 @@ rtr_latch_leaves( mtr->upgrade_buffer_fix(block_savepoint, RW_X_LATCH); - right_page_no = btr_page_get_next(block->page.frame); + right_page_no = btr_page_get_next(page); if (right_page_no != FIL_NULL) { btr_block_get(*cursor->index(), right_page_no, @@ -302,7 +304,7 @@ rtr_pcur_getnext_from_path( buf_page_make_young_if_needed(&block->page); - page = buf_block_get_frame(block); + page = block->page.frame; page_ssn = page_get_ssn_id(page); /* If there are splits, push the splitted page. @@ -467,7 +469,7 @@ rtr_pcur_getnext_from_path( const rec_t* rec = btr_cur_get_rec(btr_cur); - if (!page_rec_is_user_rec(rec)) { + if (!page_rec_is_user_rec(btr_cur_get_page(btr_cur), rec)) { mtr->commit(); mtr->start(); } else if (!index_locked) { @@ -688,7 +690,7 @@ dberr_t rtr_search_to_nth_level(ulint level, const dtuple_t *tuple, buf_page_make_young_if_needed(&block->page); - const page_t *page= buf_block_get_frame(block); + const page_t *page= block->page.frame; #ifdef UNIV_ZIP_DEBUG if (rw_latch != RW_NO_LATCH) { const page_zip_des_t *page_zip= buf_block_get_page_zip(block); @@ -863,16 +865,16 @@ dberr_t rtr_search_to_nth_level(ulint level, const dtuple_t *tuple, const rec_t *node_ptr= btr_cur_get_rec(cur); - offsets= rec_get_offsets(node_ptr, index, offsets, 0, - ULINT_UNDEFINED, &heap); - - if (page_rec_is_supremum(node_ptr)) + if (page_rec_is_supremum(btr_cur_get_page(cur), node_ptr)) { cur->low_match= 0; cur->up_match= 0; goto func_exit; } + offsets= rec_get_offsets(node_ptr, index, offsets, 0, + ULINT_UNDEFINED, &heap); + /* If we are doing insertion or record locating, remember the tree nodes we visited */ if (page_mode == PAGE_CUR_RTREE_INSERT || @@ -905,7 +907,7 @@ dberr_t rtr_search_to_nth_level(ulint level, const dtuple_t *tuple, if (add_latch) block->page.lock.s_unlock(); - ut_ad(!page_rec_is_supremum(node_ptr)); + ut_ad(!page_rec_is_supremum(page, node_ptr)); } ut_ad(page_mode == search_mode || @@ -1074,7 +1076,7 @@ bool rtr_search( const bool d= rec_get_deleted_flag( rec, cursor->index()->table->not_redundant()); - if (page_rec_is_infimum(rec) + if (page_rec_is_infimum(btr_pcur_get_page(cursor), rec) || btr_pcur_get_low_match(cursor) != dtuple_get_n_fields(tuple) || (d && latch_mode & (BTR_RTREE_DELETE_MARK | BTR_RTREE_UNDO_INS))) { @@ -1182,7 +1184,7 @@ static const rec_t* rtr_get_father_node( rec = btr_cur_get_rec(btr_cur); const ulint n_fields = dtuple_get_n_fields_cmp(tuple); - if (page_rec_is_infimum(rec) + if (page_rec_is_infimum(btr_cur_get_page(btr_cur), rec) || (btr_cur->low_match != n_fields)) { if (!rtr_pcur_getnext_from_path( tuple, PAGE_CUR_RTREE_LOCATE, btr_cur, @@ -1234,10 +1236,11 @@ rtr_page_get_father_node_ptr( ut_ad(dict_index_get_page(index) != page_no); - level = btr_page_get_level(btr_cur_get_page(cursor)); + const page_t* page = btr_cur_get_page(cursor); + level = btr_page_get_level(page); const rec_t* user_rec = btr_cur_get_rec(cursor); - ut_a(page_rec_is_user_rec(user_rec)); + ut_a(page_rec_is_user_rec(page, user_rec)); offsets = rec_get_offsets(user_rec, index, offsets, level ? 0 : index->n_fields, @@ -1285,8 +1288,7 @@ rtr_page_get_father_block( btr_cur_t* cursor) /*!< out: cursor on node pointer record, its page x-latched */ { - rec_t *rec= - page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame)); + rec_t *rec= page_rec_get_first(btr_cur_get_page(cursor)); if (!rec) return nullptr; cursor->page_cur.rec= rec; @@ -1690,7 +1692,7 @@ rtr_cur_restore_position( buf_page_make_young_if_needed(&page_cursor->block->page); /* Get the page SSN */ - page = buf_block_get_frame(page_cursor->block); + page = page_cur_get_page(page_cursor); page_ssn = page_get_ssn_id(page); if (page_cur_search_with_match(tuple, PAGE_CUR_LE, @@ -2011,7 +2013,7 @@ rtr_cur_search_with_match( ut_ad(dict_index_is_spatial(index)); - page = buf_block_get_frame(block); + page = block->page.frame; const ulint level = btr_page_get_level(page); const ulint n_core = level ? 0 : index->n_fields; @@ -2021,7 +2023,8 @@ rtr_cur_search_with_match( mode = PAGE_CUR_WITHIN; } - rec = page_dir_slot_get_rec_validate(page_dir_get_nth_slot(page, 0)); + rec = page_dir_slot_get_rec_validate( + page, page_dir_get_nth_slot(page, 0)); if (UNIV_UNLIKELY(!rec)) { return false; @@ -2030,8 +2033,8 @@ rtr_cur_search_with_match( last_rec = rec; best_rec = rec; - if (page_rec_is_infimum(rec)) { - rec = page_rec_get_next_const(rec); + if (page_rec_is_infimum(page, rec)) { + rec = page_rec_get_next(page, rec); if (UNIV_UNLIKELY(!rec)) { return false; } @@ -2039,7 +2042,8 @@ rtr_cur_search_with_match( /* Check insert tuple size is larger than first rec, and try to avoid it if possible */ - if (mode == PAGE_CUR_RTREE_INSERT && !page_rec_is_supremum(rec)) { + if (mode == PAGE_CUR_RTREE_INSERT + && !page_rec_is_supremum(page, rec)) { ulint new_rec_size = rec_get_converted_size(index, tuple, 0); @@ -2059,11 +2063,11 @@ rtr_cur_search_with_match( && !page_has_prev(page) && page_get_n_recs(page) >= 2) { - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); } } - while (!page_rec_is_supremum(rec)) { + while (!page_rec_is_supremum(page, rec)) { if (!n_core) { switch (mode) { case PAGE_CUR_CONTAIN: @@ -2228,11 +2232,11 @@ rtr_cur_search_with_match( last_rec = rec; - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); } /* All records on page are searched */ - if (rec && page_rec_is_supremum(rec)) { + if (rec && page_rec_is_supremum(page, rec)) { if (!n_core) { if (!found) { /* No match case, if it is for insertion, @@ -2328,7 +2332,7 @@ rtr_cur_search_with_match( #ifdef UNIV_DEBUG /* Verify that we are positioned at the same child page as pushed in the path stack */ - if (!n_core && (!page_rec_is_supremum(rec) || found) + if (!n_core && (!page_rec_is_supremum(page, rec) || found) && mode != PAGE_CUR_RTREE_INSERT) { ulint page_no; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d878d699510e8..12e1e40e3e9ea 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -17670,11 +17670,8 @@ innodb_make_page_dirty(THD*, st_mysql_sys_var*, void*, const void* save) if (block != NULL) { ib::info() << "Dirtying page: " << block->page.id(); - mtr.write<1,mtr_t::FORCED>(*block, - block->page.frame - + FIL_PAGE_SPACE_ID, - block->page.frame - [FIL_PAGE_SPACE_ID]); + byte* space_id = block->page.frame + FIL_PAGE_SPACE_ID; + mtr.write<1,mtr_t::FORCED>(*block, space_id, *space_id); } mtr.commit(); log_write_up_to(mtr.commit_lsn(), true); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 471d6915159f7..c3988413c31b4 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2120,7 +2120,6 @@ static bool innobase_table_is_empty(const dict_table_t *table, btr_pcur_t pcur; buf_block_t *block; page_cur_t *cur; - rec_t *rec; bool next_page= false; mtr.start(); @@ -2130,7 +2129,8 @@ static bool innobase_table_is_empty(const dict_table_t *table, mtr.commit(); return false; } - rec= page_rec_get_next(btr_pcur_get_rec(&pcur)); + page_t *page= btr_pcur_get_page(&pcur); + rec_t *rec= page_rec_get_next(page, btr_pcur_get_rec(&pcur)); if (UNIV_UNLIKELY(!rec)) goto non_empty; if (rec_is_metadata(rec, *clust_index)) @@ -2160,14 +2160,15 @@ static bool innobase_table_is_empty(const dict_table_t *table, mtr.rollback_to_savepoint(s - 2, s - 1); } + page= btr_pcur_get_page(&pcur); rec= page_cur_get_rec(cur); - if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) + if (rec_get_deleted_flag(rec, page_is_comp(page))) { if (ignore_delete_marked) goto scan_leaf; goto non_empty; } - else if (!page_rec_is_supremum(rec)) + else if (!page_rec_is_supremum(page, rec)) goto non_empty; else { @@ -6086,8 +6087,10 @@ static bool innobase_instant_try( ut_ad(btr_pcur_is_before_first_on_page(&pcur)); buf_block_t* block = btr_pcur_get_block(&pcur); - ut_ad(page_is_leaf(block->page.frame)); - ut_ad(!page_has_prev(block->page.frame)); + page_t* page = btr_pcur_get_page(&pcur); + + ut_ad(page_is_leaf(page)); + ut_ad(!page_has_prev(page)); ut_ad(!buf_block_get_page_zip(block)); const rec_t* rec = btr_pcur_move_to_next_on_page(&pcur); if (UNIV_UNLIKELY(!rec)) { @@ -6101,12 +6104,12 @@ static bool innobase_instant_try( const bool is_root = id.page_no() == index->page; if (rec_is_metadata(rec, *index)) { - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); if (is_root && !rec_is_alter_metadata(rec, *index) && !index->table->instant - && !page_has_next(block->page.frame) - && page_rec_is_last(rec, block->page.frame)) { + && !page_has_next(page) + && page_rec_is_last(page, rec)) { goto empty_table; } @@ -6195,12 +6198,12 @@ static bool innobase_instant_try( } ut_free(pcur.old_rec_buf); goto func_exit; - } else if (is_root && page_rec_is_supremum(rec) + } else if (is_root && page_rec_is_supremum(page, rec) && !index->table->instant) { empty_table: /* The table is empty. */ - ut_ad(fil_page_index_page_check(block->page.frame)); - ut_ad(!page_has_siblings(block->page.frame)); + ut_ad(fil_page_index_page_check(page)); + ut_ad(!page_has_siblings(page)); ut_ad(block->page.id().page_no() == index->page); /* MDEV-17383: free metadata BLOBs! */ btr_page_empty(block, NULL, index, 0, &mtr); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 0e520a174da07..54357d04ff1c0 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -4091,8 +4091,7 @@ i_s_innodb_buffer_page_get_info( return; } - page_info->compressed_only = !bpage->frame, - frame = bpage->frame; + frame = bpage->frame, page_info->compressed_only = !frame; if (UNIV_LIKELY(frame != nullptr)) { #ifdef BTR_CUR_HASH_ADAPT /* Note: this may be a false positive, that diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index a7a32e6720316..381ec6588a2f4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -416,7 +416,8 @@ ibuf_init_at_db_start(void) fseg_n_reserved_pages(*header_page, IBUF_HEADER + IBUF_TREE_SEG_HEADER - + header_page->page.frame, &ibuf.seg_size, &mtr); + + header_page->page.frame, + &ibuf.seg_size, &mtr); do { IF_DBUG(if (_db_keyword_(nullptr, "intermittent_read_failure", @@ -428,7 +429,7 @@ ibuf_init_at_db_start(void) buf_page_get_gen(page_id_t(IBUF_SPACE_ID, FSP_IBUF_TREE_ROOT_PAGE_NO), 0, RW_X_LATCH, nullptr, BUF_GET, &mtr, &err)) { - root = buf_block_get_frame(block); + root = block->page.frame; } else { goto err_exit; } @@ -1812,12 +1813,12 @@ static bool ibuf_add_free_page() return false; } + page_t* page = block->page.frame; ut_ad(block->page.lock.not_recursive()); ibuf_enter(&mtr); mysql_mutex_lock(&ibuf_mutex); - mtr.write<2>(*block, block->page.frame + FIL_PAGE_TYPE, - FIL_PAGE_IBUF_FREE_LIST); + mtr.write<2>(*block, page + FIL_PAGE_TYPE, FIL_PAGE_IBUF_FREE_LIST); buf_block_t* ibuf_root = ibuf_tree_root_get(&mtr); if (UNIV_UNLIKELY(!ibuf_root)) { corrupted: @@ -1830,9 +1831,10 @@ static bool ibuf_add_free_page() /* Add the page to the free list and update the ibuf size data */ - err = flst_add_last(ibuf_root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, - block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, - fil_system.sys_space->free_limit, &mtr); + err = flst_add_last(ibuf_root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + + ibuf_root->page.frame, + block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE + + page, fil_system.sys_space->free_limit, &mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { goto corrupted; } @@ -1890,15 +1892,15 @@ static void ibuf_remove_free_page() } buf_block_t* root = ibuf_tree_root_get(&mtr); + byte* ibuf_free; if (UNIV_UNLIKELY(!root)) { goto early_exit; } const auto root_savepoint = mtr.get_savepoint() - 1; - const uint32_t page_no = flst_get_last(PAGE_HEADER - + PAGE_BTR_IBUF_FREE_LIST - + root->page.frame).page; + ibuf_free = PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST + root->page.frame; + const uint32_t page_no = flst_get_last(ibuf_free).page; if (page_no >= fil_system.sys_space->free_limit) { goto early_exit; @@ -1939,9 +1941,10 @@ static void ibuf_remove_free_page() if (buf_block_t* block = buf_page_get_gen(page_id, 0, RW_X_LATCH, nullptr, BUF_GET, &mtr, &err)) { - err = flst_remove(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, + err = flst_remove(root, ibuf_free, block, - PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE + + block->page.frame, fil_system.sys_space->free_limit, &mtr); } @@ -1999,11 +2002,11 @@ ibuf_free_excess_pages(void) } #ifdef UNIV_DEBUG -# define ibuf_get_merge_page_nos(rec,mtr,ids,pages,n_stored) \ - ibuf_get_merge_page_nos_func(rec,mtr,ids,pages,n_stored) +# define ibuf_get_merge_page_nos(cur,mtr,ids,pages,n_stored) \ + ibuf_get_merge_page_nos_func(cur,mtr,ids,pages,n_stored) #else /* UNIV_DEBUG */ -# define ibuf_get_merge_page_nos(rec,mtr,ids,pages,n_stored) \ - ibuf_get_merge_page_nos_func(rec,ids,pages,n_stored) +# define ibuf_get_merge_page_nos(cur,mtr,ids,pages,n_stored) \ + ibuf_get_merge_page_nos_func(cur,ids,pages,n_stored) #endif /* UNIV_DEBUG */ /*********************************************************************//** @@ -2014,7 +2017,7 @@ static ulint ibuf_get_merge_page_nos_func( /*=========================*/ - const rec_t* rec, /*!< in: insert buffer record */ + const btr_cur_t*cur, /*!< in: cursor on change buffer leaf page */ #ifdef UNIV_DEBUG mtr_t* mtr, /*!< in: mini-transaction holding rec */ #endif /* UNIV_DEBUG */ @@ -2037,15 +2040,18 @@ ibuf_get_merge_page_nos_func( ulint limit; ulint n_pages; + const page_t* page = btr_cur_get_page(cur); + const rec_t* rec = btr_cur_get_rec(cur); + ut_ad(mtr->memo_contains_page_flagged(rec, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_S_FIX)); ut_ad(ibuf_inside(mtr)); *n_stored = 0; - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { - rec = page_rec_get_prev_const(rec); + rec = page_rec_get_prev(page, rec); if (UNIV_UNLIKELY(!rec)) { corruption: ut_ad("corrupted page" == 0); @@ -2053,9 +2059,9 @@ ibuf_get_merge_page_nos_func( } } - if (page_rec_is_infimum(rec)) { - rec = page_rec_get_next_const(rec); - if (!rec || page_rec_is_supremum(rec)) { + if (page_rec_is_infimum(page, rec)) { + rec = page_rec_get_next(page, rec); + if (!rec || page_rec_is_supremum(page, rec)) { return 0; } } @@ -2073,7 +2079,7 @@ ibuf_get_merge_page_nos_func( '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)) { + while (!page_rec_is_infimum(page, rec) && n_pages < limit) { rec_page_no = ibuf_rec_get_page_no(mtr, rec); rec_space_id = ibuf_rec_get_space(mtr, rec); @@ -2093,12 +2099,12 @@ ibuf_get_merge_page_nos_func( prev_page_no = rec_page_no; prev_space_id = rec_space_id; - if (UNIV_UNLIKELY(!(rec = page_rec_get_prev_const(rec)))) { + if (UNIV_UNLIKELY(!(rec = page_rec_get_prev(page, rec)))) { goto corruption; } } - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, 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 @@ -2110,7 +2116,7 @@ ibuf_get_merge_page_nos_func( volume_for_page = 0; while (*n_stored < limit && rec) { - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { /* When no more records available, mark this with another 'impossible' pair of space id, page no */ rec_page_no = 1; @@ -2172,7 +2178,7 @@ ibuf_get_merge_page_nos_func( prev_page_no = rec_page_no; prev_space_id = rec_space_id; - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); } #ifdef UNIV_IBUF_DEBUG @@ -2198,7 +2204,7 @@ ibuf_get_user_rec( do { const rec_t* rec = btr_pcur_get_rec(pcur); - if (page_rec_is_user_rec(rec)) { + if (page_rec_is_user_rec(btr_pcur_get_page(pcur), rec)) { return(rec); } } while (btr_pcur_move_to_next(pcur, mtr)); @@ -2438,7 +2444,7 @@ ATTRIBUTE_COLD ulint ibuf_contract() } ulint n_pages = 0; - sum_sizes = ibuf_get_merge_page_nos(btr_cur_get_rec(&cur), &mtr, + sum_sizes = ibuf_get_merge_page_nos(&cur, &mtr, space_ids, page_nos, &n_pages); ibuf_mtr_commit(&mtr); @@ -2730,11 +2736,11 @@ ibuf_get_volume_buffered( } rec = btr_pcur_get_rec(pcur); - page = page_align(rec); + page = btr_pcur_get_page(pcur); ut_ad(page_validate(page, ibuf.index)); - if (page_rec_is_supremum(rec) - && UNIV_UNLIKELY(!(rec = page_rec_get_prev_const(rec)))) { + if (page_rec_is_supremum(page, rec) + && UNIV_UNLIKELY(!(rec = page_rec_get_prev(page, rec)))) { corruption: ut_ad("corrupted page" == 0); return srv_page_size; @@ -2742,9 +2748,7 @@ ibuf_get_volume_buffered( uint32_t prev_page_no; - for (; !page_rec_is_infimum(rec); ) { - ut_ad(page_align(rec) == page); - + while (!page_rec_is_infimum(page, rec)) { if (page_no != ibuf_rec_get_page_no(mtr, rec) || space != ibuf_rec_get_space(mtr, rec)) { @@ -2755,7 +2759,7 @@ ibuf_get_volume_buffered( mtr, rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); - if (UNIV_UNLIKELY(!(rec = page_rec_get_prev_const(rec)))) { + if (UNIV_UNLIKELY(!(rec = page_rec_get_prev(page, rec)))) { goto corruption; } } @@ -2772,7 +2776,7 @@ ibuf_get_volume_buffered( if (buf_block_t* block = buf_page_get(page_id_t(IBUF_SPACE_ID, prev_page_no), 0, RW_X_LATCH, mtr)) { - prev_page = buf_block_get_frame(block); + prev_page = block->page.frame; ut_ad(page_validate(prev_page, ibuf.index)); } else { return srv_page_size; @@ -2786,7 +2790,7 @@ ibuf_get_volume_buffered( return srv_page_size; } - rec = page_rec_get_prev_const(page_get_supremum_rec(prev_page)); + rec = page_rec_get_prev(prev_page, page_get_supremum_rec(prev_page)); if (UNIV_UNLIKELY(!rec)) { goto corruption; @@ -2795,7 +2799,7 @@ ibuf_get_volume_buffered( for (;;) { ut_ad(page_align(rec) == prev_page); - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(prev_page, rec)) { /* We cannot go to yet a previous page, because we do not have the x-latch on it, and cannot acquire one @@ -2814,7 +2818,9 @@ ibuf_get_volume_buffered( mtr, rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); - if (UNIV_UNLIKELY(!(rec = page_rec_get_prev_const(rec)))) { + rec = page_rec_get_prev(prev_page, rec); + + if (UNIV_UNLIKELY(!rec)) { goto corruption; } } @@ -2822,12 +2828,12 @@ ibuf_get_volume_buffered( count_later: rec = btr_pcur_get_rec(pcur); - if (!page_rec_is_supremum(rec)) { - rec = page_rec_get_next_const(rec); + if (!page_rec_is_supremum(page, rec)) { + rec = page_rec_get_next(page, rec); } - for (; !page_rec_is_supremum(rec); - rec = page_rec_get_next_const(rec)) { + for (; !page_rec_is_supremum(page, rec); + rec = page_rec_get_next(page, rec)) { if (UNIV_UNLIKELY(!rec)) { return srv_page_size; } @@ -2854,7 +2860,7 @@ ibuf_get_volume_buffered( if (buf_block_t* block = buf_page_get(page_id_t(IBUF_SPACE_ID, next_page_no), 0, RW_X_LATCH, mtr)) { - next_page = buf_block_get_frame(block); + next_page = block->page.frame; ut_ad(page_validate(next_page, ibuf.index)); } else { return srv_page_size; @@ -2868,11 +2874,10 @@ ibuf_get_volume_buffered( return 0; } - rec = page_get_infimum_rec(next_page); - rec = page_rec_get_next_const(rec); + rec = page_rec_get_first(next_page); - for (; ; rec = page_rec_get_next_const(rec)) { - if (!rec || page_rec_is_supremum(rec)) { + for (; ; rec = page_rec_get_next(next_page, rec)) { + if (!rec || page_rec_is_supremum(next_page, rec)) { /* We give up */ return(srv_page_size); } @@ -2939,11 +2944,11 @@ ibuf_update_max_tablespace_id(void) } #ifdef UNIV_DEBUG -# define ibuf_get_entry_counter_low(mtr,rec,space,page_no) \ - ibuf_get_entry_counter_low_func(mtr,rec,space,page_no) +# define ibuf_get_entry_counter_low(mtr,page_id,rec) \ + ibuf_get_entry_counter_low_func(mtr,page_id,rec) #else /* UNIV_DEBUG */ -# define ibuf_get_entry_counter_low(mtr,rec,space,page_no) \ - ibuf_get_entry_counter_low_func(rec,space,page_no) +# define ibuf_get_entry_counter_low(mtr,page_id,rec) \ + ibuf_get_entry_counter_low_func(page_id,rec) #endif /****************************************************************//** Helper function for ibuf_get_entry_counter_func. Checks if rec is for @@ -2959,9 +2964,8 @@ ibuf_get_entry_counter_low_func( #ifdef UNIV_DEBUG mtr_t* mtr, /*!< in: mini-transaction of rec */ #endif /* UNIV_DEBUG */ - const rec_t* rec, /*!< in: insert buffer record */ - ulint space, /*!< in: space id */ - ulint page_no) /*!< in: page number */ + const page_id_t page_id, /*!< in: page identifier */ + const rec_t* rec) /*!< in: insert buffer record */ { ulint counter; const byte* field; @@ -2981,7 +2985,7 @@ ibuf_get_entry_counter_low_func( ut_a(len == 4); - if (mach_read_from_4(field) != space) { + if (mach_read_from_4(field) != page_id.space()) { return(0); } @@ -2990,7 +2994,7 @@ ibuf_get_entry_counter_low_func( field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_PAGE, &len); ut_a(len == 4); - if (mach_read_from_4(field) != page_no) { + if (mach_read_from_4(field) != page_id.page_no()) { return(0); } @@ -3013,11 +3017,11 @@ ibuf_get_entry_counter_low_func( } #ifdef UNIV_DEBUG -# define ibuf_get_entry_counter(space,page_no,rec,mtr,exact_leaf) \ - ibuf_get_entry_counter_func(space,page_no,rec,mtr,exact_leaf) +# define ibuf_get_entry_counter(mtr,page_id,pcur) \ + ibuf_get_entry_counter_func(mtr,page_id,pcur) #else /* UNIV_DEBUG */ -# define ibuf_get_entry_counter(space,page_no,rec,mtr,exact_leaf) \ - ibuf_get_entry_counter_func(space,page_no,rec,exact_leaf) +# define ibuf_get_entry_counter(mtr,page_id,pcur) \ + ibuf_get_entry_counter_func(page_id,pcur) #endif /* UNIV_DEBUG */ /****************************************************************//** @@ -3029,31 +3033,28 @@ static ulint ibuf_get_entry_counter_func( /*========================*/ - ulint space, /*!< in: space id of entry */ - ulint page_no, /*!< in: page number of entry */ - const rec_t* rec, /*!< in: the record preceding the - insertion point */ #ifdef UNIV_DEBUG mtr_t* mtr, /*!< in: mini-transaction */ #endif /* UNIV_DEBUG */ - ibool only_leaf) /*!< in: TRUE if this is the only - leaf page that can contain entries - for (space,page_no), that is, there - was no exact match for (space,page_no) - in the node pointer */ + const page_id_t page_id, /*!< in: page identifier of entry */ + const btr_pcur_t*pcur) /*!< in: cursor on the record preceding the + insertion point */ { ut_ad(ibuf_inside(mtr)); - ut_ad(mtr->memo_contains_page_flagged(rec, MTR_MEMO_PAGE_X_FIX)); - ut_ad(page_validate(page_align(rec), ibuf.index)); + const page_t* page = btr_pcur_get_page(pcur); + const page_t* rec = btr_pcur_get_rec(pcur); + ut_ad(mtr->memo_contains_page_flagged(page, MTR_MEMO_PAGE_X_FIX)); + ut_ad(page_validate(page, ibuf.index)); - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { /* This is just for safety. The record should be a page infimum or a user record. */ ut_ad(0); return(ULINT_UNDEFINED); - } else if (!page_rec_is_infimum(rec)) { - return(ibuf_get_entry_counter_low(mtr, rec, space, page_no)); - } else if (only_leaf || !page_has_prev(page_align(rec))) { + } else if (!page_rec_is_infimum(page, rec)) { + return ibuf_get_entry_counter_low(mtr, page_id, rec); + } else if (btr_pcur_get_btr_cur(pcur)->low_match + < IBUF_REC_FIELD_METADATA || !page_has_prev(page)) { /* The parent node pointer did not contain the searched for (space, page_no), which means that the search ended on the correct page regardless of the @@ -3289,10 +3290,7 @@ ibuf_insert_low( insert. This can change the insert position, which can result in the need to abort in some cases. */ ulint counter = ibuf_get_entry_counter( - page_id.space(), page_id.page_no(), - btr_pcur_get_rec(&pcur), &mtr, - btr_pcur_get_btr_cur(&pcur)->low_match - < IBUF_REC_FIELD_METADATA); + &mtr, page_id, &pcur); dfield_t* field; if (counter == ULINT_UNDEFINED) { @@ -3326,7 +3324,7 @@ ibuf_insert_low( /* If this is the root page, update ibuf.empty. */ if (block->page.id().page_no() == FSP_IBUF_TREE_ROOT_PAGE_NO) { - const page_t* root = buf_block_get_frame(block); + const page_t* root = block->page.frame; ut_ad(page_get_space_id(root) == IBUF_SPACE_ID); ut_ad(page_get_page_no(root) @@ -3575,7 +3573,7 @@ ibuf_insert_to_index_page( mtr_t* mtr) /*!< in: mtr */ { page_cur_t page_cur; - page_t* page = buf_block_get_frame(block); + page_t* page = block->page.frame; rec_t* rec; rec_offs* offsets; mem_heap_t* heap; @@ -3601,9 +3599,9 @@ ibuf_insert_to_index_page( return DB_CORRUPTION; } - rec = page_rec_get_next(page_get_infimum_rec(page)); + rec = page_rec_get_first(page); - if (!rec || page_rec_is_supremum(rec)) { + if (!rec || page_rec_is_supremum(page, rec)) { return DB_CORRUPTION; } @@ -3806,8 +3804,8 @@ ibuf_delete( nullptr) && low_match == dtuple_get_n_fields(entry)) { page_zip_des_t* page_zip= buf_block_get_page_zip(block); - page_t* page = buf_block_get_frame(block); rec_t* rec = page_cur_get_rec(&page_cur); + page_t* page = page_cur_get_page(&page_cur); /* TODO: the below should probably be a separate function, it's a bastardized version of btr_cur_optimistic_delete. */ @@ -3923,7 +3921,7 @@ bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur, dberr_t err; ut_ad(ibuf_inside(mtr)); - ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur))); + ut_ad(btr_pcur_is_on_user_rec(pcur)); ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_id.page_no()); ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) @@ -3979,9 +3977,9 @@ bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur, btr_pcur_get_btr_cur(pcur), BTR_CREATE_FLAG, false, mtr); ut_a(err == DB_SUCCESS); - - ibuf_size_update(ibuf_root->page.frame); - ibuf.empty = page_is_empty(ibuf_root->page.frame); + const page_t *root = ibuf_root->page.frame; + ibuf_size_update(root); + ibuf.empty = page_is_empty(root); } mysql_mutex_unlock(&ibuf_mutex); @@ -4097,12 +4095,14 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block, buf_block_t* bitmap_page = ibuf_bitmap_get_map_page( page_id, zip_size, &mtr); - if (bitmap_page - && fil_page_get_type(bitmap_page->page.frame) - != FIL_PAGE_TYPE_ALLOCATED) { - bitmap_bits = ibuf_bitmap_page_get_bits( - bitmap_page->page.frame, page_id, zip_size, - IBUF_BITMAP_BUFFERED, &mtr); + if (bitmap_page) { + const page_t* frame = bitmap_page->page.frame; + if (fil_page_get_type(frame) + != FIL_PAGE_TYPE_ALLOCATED) { + bitmap_bits = ibuf_bitmap_page_get_bits( + frame, page_id, zip_size, + IBUF_BITMAP_BUFFERED, &mtr); + } } ibuf_mtr_commit(&mtr); @@ -4130,19 +4130,25 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block, } } - if (!block) { - } else if (!fil_page_index_page_check(block->page.frame) - || !page_is_leaf(block->page.frame)) { - space->set_corrupted(); - err = DB_CORRUPTION; - block = nullptr; - } else { - /* Move the ownership of the x-latch on the page to this OS - thread, so that we can acquire a second x-latch on it. This - is needed for the insert operations to the index page to pass - the debug checks. */ + page_t* page = nullptr; - block->page.lock.claim_ownership(); + if (block) { + page = block->page.frame; + if (!fil_page_index_page_check(page) + || !page_is_leaf(page)) { + space->set_corrupted(); + err = DB_CORRUPTION; + block = nullptr; + page = nullptr; + } else { + /* Move the ownership of the x-latch on the + page to this OS thread, so that we can acquire + a second x-latch on it. This is needed for the + insert operations to the index page to pass + the debug checks. */ + + block->page.lock.claim_ownership(); + } } mem_heap_t* heap = mem_heap_create(512); @@ -4197,7 +4203,8 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block, || ibuf_rec_get_space(&mtr, rec) != page_id.space()) { if (block != NULL) { - page_header_reset_last_insert(block, &mtr); + page_header_reset_last_insert( + block, page, &mtr); } goto reset_bit; @@ -4218,7 +4225,7 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block, dict_index_t* dummy_index; ibuf_op_t op = ibuf_rec_get_op_type(&mtr, rec); - max_trx_id = page_get_max_trx_id(page_align(rec)); + max_trx_id = page_get_max_trx_id(block->page.frame); page_update_max_trx_id(block, buf_block_get_page_zip(block), max_trx_id, &mtr); @@ -4231,7 +4238,7 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block, dummy_index->table->space = space; dummy_index->table->space_id = space->id; - ut_ad(page_validate(block->page.frame, dummy_index)); + ut_ad(page_validate(page, dummy_index)); switch (op) { case IBUF_OP_INSERT: @@ -4260,7 +4267,8 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block, before latching any further pages. Store and restore the cursor position. */ ut_ad(rec == btr_pcur_get_rec(&pcur)); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec( + btr_pcur_get_page(&pcur), rec)); ut_ad(ibuf_rec_get_page_no(&mtr, rec) == page_id.page_no()); ut_ad(ibuf_rec_get_space(&mtr, rec) @@ -4520,9 +4528,9 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) mtr.commit(); return DB_CORRUPTION; } + const byte* bitmap = bitmap_page->page.frame; - if (buf_is_zeroes(span(bitmap_page->page.frame, - physical_size))) { + if (buf_is_zeroes(span(bitmap, physical_size))) { /* This means we got all-zero page instead of ibuf bitmap page. The subsequent page should be all-zero pages. */ @@ -4533,7 +4541,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) buf_block_t* block = buf_page_get( page_id_t(space->id, curr_page), zip_size, RW_S_LATCH, &mtr); - page_t* page = buf_block_get_frame(block); + page_t* page = block->page.frame; ut_ad(buf_is_zeroes(span( page, physical_size))); @@ -4549,7 +4557,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) const page_id_t cur_page_id(space->id, offset); if (ibuf_bitmap_page_get_bits( - bitmap_page->page.frame, + bitmap, cur_page_id, zip_size, IBUF_BITMAP_IBUF, &mtr)) { @@ -4566,7 +4574,7 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) } if (ibuf_bitmap_page_get_bits( - bitmap_page->page.frame, + bitmap, cur_page_id, zip_size, IBUF_BITMAP_BUFFERED, &mtr)) { diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 83bdaa9794917..a0dbd937f9564 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -327,7 +327,7 @@ inline void btr_set_min_rec_mark(rec_t *rec, const buf_block_t &block, ut_ad(!page_is_leaf(block.page.frame)); ut_ad(has_prev == page_has_prev(block.page.frame)); - rec-= page_rec_is_comp(rec) ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS; + rec-= page_is_comp(block.page.frame) ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS; if (block.page.zip.data) /* This flag is computed from other contents on a ROW_FORMAT=COMPRESSED @@ -496,15 +496,16 @@ btr_print_index( Checks the size and number of fields in a record based on the definition of the index. @return TRUE if ok */ -ibool +bool btr_index_rec_validate( /*===================*/ + const page_t* page, /*!< in: index page */ const rec_t* rec, /*!< in: index record */ const dict_index_t* index, /*!< in: index */ - ibool dump_on_error) /*!< in: TRUE if the function + bool dump_on_error) /*!< in: TRUE if the function should print hex dump of record and page on error */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); /**************************************************************//** Checks the consistency of an index tree. @return DB_SUCCESS if ok, error code if not */ diff --git a/storage/innobase/include/btr0btr.inl b/storage/innobase/include/btr0btr.inl index 9a9e39b6b4c84..91310e7f48180 100644 --- a/storage/innobase/include/btr0btr.inl +++ b/storage/innobase/include/btr0btr.inl @@ -40,14 +40,16 @@ btr_page_get_index_id( /** Set PAGE_LEVEL. @param[in,out] block buffer block +@param[in,out] page buffer block frame @param[in] level page level @param[in,out] mtr mini-transaction */ inline -void btr_page_set_level(buf_block_t *block, ulint level, mtr_t *mtr) +void btr_page_set_level(buf_block_t *block, page_t *page, ulint level, + mtr_t *mtr) { ut_ad(level <= BTR_MAX_NODE_LEVEL); constexpr uint16_t field= PAGE_HEADER + PAGE_LEVEL; - byte *b= my_assume_aligned<2>(&block->page.frame[field]); + byte *b= my_assume_aligned<2>(&page[field]); if (mtr->write<2,mtr_t::MAYBE_NOP>(*block, b, level) && UNIV_LIKELY_NULL(block->page.zip.data)) memcpy_aligned<2>(&block->page.zip.data[field], b, 2); @@ -55,12 +57,14 @@ void btr_page_set_level(buf_block_t *block, ulint level, mtr_t *mtr) /** Set FIL_PAGE_NEXT. @param[in,out] block buffer block +@param[in,out] page buffer block frame @param[in] next number of successor page @param[in,out] mtr mini-transaction */ -inline void btr_page_set_next(buf_block_t *block, ulint next, mtr_t *mtr) +inline void btr_page_set_next(buf_block_t *block, page_t *page, ulint next, + mtr_t *mtr) { constexpr uint16_t field= FIL_PAGE_NEXT; - byte *b= my_assume_aligned<4>(&block->page.frame[field]); + byte *b= my_assume_aligned<4>(&page[field]); if (mtr->write<4,mtr_t::MAYBE_NOP>(*block, b, next) && UNIV_LIKELY_NULL(block->page.zip.data)) memcpy_aligned<4>(&block->page.zip.data[field], b, 4); @@ -68,12 +72,14 @@ inline void btr_page_set_next(buf_block_t *block, ulint next, mtr_t *mtr) /** Set FIL_PAGE_PREV. @param[in,out] block buffer block +@param[in,out] page buffer block frame @param[in] prev number of predecessor page @param[in,out] mtr mini-transaction */ -inline void btr_page_set_prev(buf_block_t *block, ulint prev, mtr_t *mtr) +inline void btr_page_set_prev(buf_block_t *block, page_t *page, ulint prev, + mtr_t *mtr) { constexpr uint16_t field= FIL_PAGE_PREV; - byte *b= my_assume_aligned<4>(&block->page.frame[field]); + byte *b= my_assume_aligned<4>(&page[field]); if (mtr->write<4,mtr_t::MAYBE_NOP>(*block, b, prev) && UNIV_LIKELY_NULL(block->page.zip.data)) memcpy_aligned<4>(&block->page.zip.data[field], b, 4); diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h index 9fcea86d95dee..8979e42d2fcb5 100644 --- a/storage/innobase/include/btr0bulk.h +++ b/storage/innobase/include/btr0bulk.h @@ -151,12 +151,13 @@ class PageBulk rec_t* getSplitRec(); /** Copy all records after split rec including itself. - @param[in] rec split rec */ - void copyIn(rec_t* split_rec); + @param page page to copy from + @param rec first record to copy */ + void copyIn(const page_t *page, const rec_t *rec); - /** Remove all records after split rec including itself. - @param[in] rec split rec */ - void copyOut(rec_t* split_rec); + /** Remove all records starting with split rec. + @param split_rec first record to remove */ + inline void copyOut(rec_t *split_rec); /** Set next page @param[in] next_page_no next page no */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index f6abc9f5e5265..63b1a6adb1a55 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -66,6 +66,7 @@ enum { #include "que0types.h" #include "row0types.h" +#define btr_cur_get_page(cursor) ((cursor)->block()->page.frame) #define btr_cur_get_page_cur(cursor) (&(cursor)->page_cur) #define btr_cur_get_block(cursor) ((cursor)->page_cur.block) #define btr_cur_get_rec(cursor) ((cursor)->page_cur.rec) @@ -79,14 +80,6 @@ btr_cur_get_page_zip( /*=================*/ btr_cur_t* cursor);/*!< in: tree cursor */ /*********************************************************//** -Returns the page of a tree cursor. -@return pointer to page */ -UNIV_INLINE -page_t* -btr_cur_get_page( -/*=============*/ - btr_cur_t* cursor);/*!< in: tree cursor */ -/*********************************************************//** Returns the index of a cursor. @param cursor b-tree cursor @return index */ diff --git a/storage/innobase/include/btr0cur.inl b/storage/innobase/include/btr0cur.inl index 955cf34288e23..5981b1465c9e8 100644 --- a/storage/innobase/include/btr0cur.inl +++ b/storage/innobase/include/btr0cur.inl @@ -48,18 +48,6 @@ btr_cur_get_page_zip( return(buf_block_get_page_zip(btr_cur_get_block(cursor))); } -/*********************************************************//** -Returns the page of a tree cursor. -@return pointer to page */ -UNIV_INLINE -page_t* -btr_cur_get_page( -/*=============*/ - btr_cur_t* cursor) /*!< in: tree cursor */ -{ - return(page_align(page_cur_get_rec(&(cursor->page_cur)))); -} - /*********************************************************//** Positions a tree cursor at a given record. */ UNIV_INLINE diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 5f84328da1904..83643070b271f 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -213,7 +213,7 @@ btr_pcur_move_to_next_page( #define btr_pcur_get_btr_cur(cursor) (&(cursor)->btr_cur) #define btr_pcur_get_page_cur(cursor) (&(cursor)->btr_cur.page_cur) -#define btr_pcur_get_page(cursor) btr_pcur_get_block(cursor)->page.frame +#define btr_pcur_get_page(cursor) btr_cur_get_page(&(cursor)->btr_cur) /*********************************************************//** Checks if the persistent cursor is on a user record. */ diff --git a/storage/innobase/include/btr0pcur.inl b/storage/innobase/include/btr0pcur.inl index b827d70dc47bf..52002aa33664a 100644 --- a/storage/innobase/include/btr0pcur.inl +++ b/storage/innobase/include/btr0pcur.inl @@ -193,25 +193,23 @@ btr_pcur_move_to_next_user_rec( function may release the page latch */ mtr_t* mtr) /*!< in: mtr */ { - ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); - ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - cursor->old_rec = nullptr; + ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + cursor->old_rec= nullptr; + if (btr_pcur_is_after_last_on_page(cursor)) loop: - if (btr_pcur_is_after_last_on_page(cursor)) { - if (btr_pcur_is_after_last_in_tree(cursor) - || btr_pcur_move_to_next_page(cursor, mtr) != DB_SUCCESS) { - return(FALSE); - } - } else if (UNIV_UNLIKELY(!btr_pcur_move_to_next_on_page(cursor))) { - return false; - } + if (btr_pcur_move_to_next_page(cursor, mtr) != DB_SUCCESS) + return false; + + const rec_t *rec= btr_pcur_move_to_next_on_page(cursor); - if (btr_pcur_is_on_user_rec(cursor)) { + if (UNIV_UNLIKELY(!rec)) + return false; - return(TRUE); - } + if (page_rec_is_supremum(btr_pcur_get_page(cursor), rec)) + goto loop; - goto loop; + return true; } /*********************************************************//** diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index d403fe1243055..fa587b13f1fce 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -420,8 +420,6 @@ void buf_pool_invalidate(); --------------------------- LOWER LEVEL ROUTINES ------------------------- =========================================================================*/ -#define buf_block_get_frame(block) (block)->page.frame - /*********************************************************************//** Gets the compressed page descriptor corresponding to an uncompressed page if applicable. */ @@ -835,6 +833,12 @@ class buf_page_t return zip.ssize ? (UNIV_ZIP_SIZE_MIN >> 1) << zip.ssize : 0; } +#ifdef UNIV_DEBUG + /** @return whether the address is within the page frame */ + bool is_physical_address(const byte *p) const + { return size_t(p - frame) < physical_size(); } +#endif + /** @return the byte offset of the page within a file */ os_offset_t physical_offset() const { @@ -1679,7 +1683,7 @@ class buf_pool_t indexed by page_id_t. Protected by both mutex and page_hash.lock_get(). */ page_hash_table page_hash; - /** map of block->frame to buf_block_t blocks that belong + /** map of buf_page_t::frame to buf_block_t blocks that belong to buf_buddy_alloc(); protected by buf_pool.mutex */ hash_table_t zip_hash; Atomic_counter diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 2e25b3aed0855..b37544b3e41eb 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -105,11 +105,11 @@ inline void buf_flush_note_modification(buf_block_t *b, lsn_t start, lsn_t end) ut_d(const auto s= b->page.state()); ut_ad(s > buf_page_t::FREED); ut_ad(s < buf_page_t::READ_FIX); - ut_ad(mach_read_from_8(b->page.frame + FIL_PAGE_LSN) <= end); - mach_write_to_8(b->page.frame + FIL_PAGE_LSN, end); + byte *page_lsn= FIL_PAGE_LSN + b->page.frame; + ut_ad(mach_read_from_8(page_lsn) <= end); + mach_write_to_8(page_lsn, end); if (UNIV_LIKELY_NULL(b->page.zip.data)) - memcpy_aligned<8>(FIL_PAGE_LSN + b->page.zip.data, - FIL_PAGE_LSN + b->page.frame, 8); + memcpy_aligned<8>(FIL_PAGE_LSN + b->page.zip.data, page_lsn, 8); const lsn_t oldest_modification= b->page.oldest_modification(); diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index dc88375adb469..a47d6ec97f65b 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -501,29 +501,32 @@ fseg_free_step_not_header( Data files created before MySQL 5.1.48 may contain garbage in FIL_PAGE_TYPE. In MySQL 3.23.53, only undo log pages and index pages were tagged. Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE. -@param[in] block block with invalid FIL_PAGE_TYPE +@param[in] block block descriptor +@param[in,out] page page with invalid FIL_PAGE_TYPE @param[in] type expected page type @param[in,out] mtr mini-transaction */ ATTRIBUTE_COLD -void fil_block_reset_type(const buf_block_t& block, ulint type, mtr_t* mtr); +void fil_block_reset_type(const buf_block_t &block, page_t *page, ulint type, + mtr_t *mtr); /** Check (and if needed, reset) the page type. Data files created before MySQL 5.1.48 may contain garbage in the FIL_PAGE_TYPE field. In MySQL 3.23.53, only undo log pages and index pages were tagged. Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE. -@param[in] page_id page number +@param[in] block block descriptor @param[in,out] page page with possibly invalid FIL_PAGE_TYPE @param[in] type expected page type @param[in,out] mtr mini-transaction */ inline void fil_block_check_type( const buf_block_t& block, + page_t* page, ulint type, mtr_t* mtr) { - if (UNIV_UNLIKELY(type != fil_page_get_type(block.page.frame))) - fil_block_reset_type(block, type, mtr); + if (UNIV_UNLIKELY(type != fil_page_get_type(page))) + fil_block_reset_type(block, page, type, mtr); } /** Checks if a page address is an extent descriptor page address. @@ -536,14 +539,16 @@ inline bool fsp_descr_page(const page_id_t page_id, ulint physical_size) } /** Initialize a file page whose prior contents should be ignored. -@param[in,out] block buffer pool block */ -void fsp_apply_init_file_page(buf_block_t *block); +@param[in,out] block buffer pool block +@return the page frame */ +page_t *fsp_apply_init_file_page(buf_block_t *block); /** Initialize a file page. @param[in] space tablespace @param[in,out] block file page -@param[in,out] mtr mini-transaction */ -inline void fsp_init_file_page( +@param[in,out] mtr mini-transaction +@return the page frame */ +inline page_t* fsp_init_file_page( #ifdef UNIV_DEBUG const fil_space_t* space, #endif @@ -551,8 +556,8 @@ inline void fsp_init_file_page( { ut_d(space->modify_check(*mtr)); ut_ad(space->id == block->page.id().space()); - fsp_apply_init_file_page(block); mtr->init(block); + return fsp_apply_init_file_page(block); } #ifndef UNIV_DEBUG diff --git a/storage/innobase/include/fut0lst.h b/storage/innobase/include/fut0lst.h index 1adec365f2b9d..555673014e7c3 100644 --- a/storage/innobase/include/fut0lst.h +++ b/storage/innobase/include/fut0lst.h @@ -59,12 +59,11 @@ typedef byte flst_node_t; @param[in,out] block file page @param[in] ofs byte offset of the list base node @param[in,out] mtr mini-transaction */ -inline void flst_init(const buf_block_t* block, uint16_t ofs, mtr_t* mtr) +inline void flst_init(const buf_block_t* block, byte *ofs, mtr_t* mtr) { - ut_d(const page_t *page= block->page.frame); - ut_ad(!mach_read_from_2(FLST_LEN + ofs + page)); - ut_ad(!mach_read_from_2(FLST_FIRST + FIL_ADDR_BYTE + ofs + page)); - ut_ad(!mach_read_from_2(FLST_LAST + FIL_ADDR_BYTE + ofs + page)); + ut_ad(!mach_read_from_2(FLST_LEN + ofs)); + ut_ad(!mach_read_from_2(FLST_FIRST + FIL_ADDR_BYTE + ofs)); + ut_ad(!mach_read_from_2(FLST_LAST + FIL_ADDR_BYTE + ofs)); compile_time_assert(FIL_NULL == 0xffU * 0x1010101U); mtr->memset(block, FLST_FIRST + FIL_ADDR_PAGE + ofs, 4, 0xff); mtr->memset(block, FLST_LAST + FIL_ADDR_PAGE + ofs, 4, 0xff); @@ -85,9 +84,9 @@ void flst_init(const buf_block_t &block, byte *base, mtr_t *mtr) @param limit fil_space_t::free_limit @param mtr mini-transaction @return error code */ -dberr_t flst_add_last(buf_block_t *base, uint16_t boffset, - buf_block_t *add, uint16_t aoffset, - uint32_t limit, mtr_t *mtr) +dberr_t flst_add_last(buf_block_t *base, byte *boffset, + buf_block_t *add, byte *aoffset, + uint32_t limit, mtr_t *mtr) MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Prepend a file list node to a list. @param base base node block @@ -97,9 +96,9 @@ dberr_t flst_add_last(buf_block_t *base, uint16_t boffset, @param limit fil_space_t::free_limit @param mtr mini-transaction @return error code */ -dberr_t flst_add_first(buf_block_t *base, uint16_t boffset, - buf_block_t *add, uint16_t aoffset, - uint32_t limit, mtr_t *mtr) +dberr_t flst_add_first(buf_block_t *base, byte *boffset, + buf_block_t *add, byte *aoffset, + uint32_t limit, mtr_t *mtr) MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Remove a file list node. @param base base node block @@ -109,9 +108,9 @@ dberr_t flst_add_first(buf_block_t *base, uint16_t boffset, @param limit fil_space_t::free_limit @param mtr mini-transaction @return error code */ -dberr_t flst_remove(buf_block_t *base, uint16_t boffset, - buf_block_t *cur, uint16_t coffset, - uint32_t limit, mtr_t *mtr) +dberr_t flst_remove(buf_block_t *base, byte *boffset, + buf_block_t *cur, byte *coffset, + uint32_t limit, mtr_t *mtr) MY_ATTRIBUTE((nonnull, warn_unused_result)); /** @return the length of a list */ diff --git a/storage/innobase/include/gis0rtree.inl b/storage/innobase/include/gis0rtree.inl index 5101eeb6f7ace..6747507436e90 100644 --- a/storage/innobase/include/gis0rtree.inl +++ b/storage/innobase/include/gis0rtree.inl @@ -36,8 +36,6 @@ rtr_page_cal_mbr( mem_heap_t* heap) /*!< in: heap for the memory allocation */ { - page_t* page; - rec_t* rec; const byte* field; ulint len; rec_offs* offsets = NULL; @@ -54,9 +52,9 @@ rtr_page_cal_mbr( mbr = reinterpret_cast(rtr_mbr); - page = buf_block_get_frame(block); + const page_t* page = block->page.frame; - rec = page_rec_get_next(page_get_infimum_rec(page)); + const rec_t* rec = page_rec_get_first(page); if (UNIV_UNLIKELY(!rec)) { return; } @@ -85,12 +83,12 @@ rtr_page_cal_mbr( inc += 2 * sizeof(double); } - rec = page_rec_get_next(rec); + rec = page_rec_get_next(page, rec); if (rec == NULL) { break; } - } while (!page_rec_is_supremum(rec)); + } while (!page_rec_is_supremum(page, rec)); } /**************************************************************//** diff --git a/storage/innobase/include/ibuf0ibuf.inl b/storage/innobase/include/ibuf0ibuf.inl index 1e21f74ff2b6d..0ef8d9c9b09df 100644 --- a/storage/innobase/include/ibuf0ibuf.inl +++ b/storage/innobase/include/ibuf0ibuf.inl @@ -173,8 +173,7 @@ ibuf_index_page_calc_free_zip( merging a buffered insert to a compressed page will always succeed without reorganizing or recompressing the page, just by using the page modification log. */ - max_ins_size = page_get_max_insert_size( - buf_block_get_frame(block), 1); + max_ins_size = page_get_max_insert_size(block->page.frame, 1); page_zip = buf_block_get_page_zip(block); zip_max_ins = page_zip_max_ins_size(page_zip, @@ -203,7 +202,7 @@ ibuf_index_page_calc_free( ulint max_ins_size; max_ins_size = page_get_max_insert_size_after_reorganize( - buf_block_get_frame(block), 1); + block->page.frame, 1); return(ibuf_index_page_calc_free_bits( block->physical_size(), max_ins_size)); diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 08b9f4bcb35c8..0d23f6612c042 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -59,7 +59,7 @@ UNIV_INLINE ulint lock_get_min_heap_no( /*=================*/ - const buf_block_t* block); /*!< in: buffer block */ + const page_t* page); /*!< in: index page */ /** Discard locks for an index when purging DELETE FROM SYS_INDEXES after an aborted CREATE INDEX operation. diff --git a/storage/innobase/include/lock0lock.inl b/storage/innobase/include/lock0lock.inl index 1b9255ffb3e0a..4450610db2494 100644 --- a/storage/innobase/include/lock0lock.inl +++ b/storage/innobase/include/lock0lock.inl @@ -35,10 +35,8 @@ UNIV_INLINE ulint lock_get_min_heap_no( /*=================*/ - const buf_block_t* block) /*!< in: buffer block */ + const page_t* page) /*!< in: index page */ { - const page_t* page = block->page.frame; - if (page_is_comp(page)) { return(rec_get_heap_no_new( page diff --git a/storage/innobase/include/lock0priv.inl b/storage/innobase/include/lock0priv.inl index 3b4ebcc835b39..34e243d303fac 100644 --- a/storage/innobase/include/lock0priv.inl +++ b/storage/innobase/include/lock0priv.inl @@ -47,8 +47,8 @@ lock_clust_rec_some_has_impl( const dict_index_t* index, /*!< in: clustered index */ const rec_offs* offsets)/*!< in: rec_get_offsets(rec, index) */ { - ut_ad(dict_index_is_clust(index)); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(index->is_primary()); + ut_ad(page_rec_is_user_rec(page_align(rec), rec)); return(row_get_rec_trx_id(rec, index, offsets)); } diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h index d34a62e7bb2f1..27b55af5581d7 100644 --- a/storage/innobase/include/mtr0log.h +++ b/storage/innobase/include/mtr0log.h @@ -210,19 +210,20 @@ inline bool mtr_t::write(const buf_block_t &block, void *ptr, V val) p--; } ::memcpy(ptr, buf, l); - memcpy_low(block, static_cast - (ut_align_offset(p, srv_page_size)), p, end - p); + memcpy(block, p, end - p); return true; } /** Log an initialization of a string of bytes. -@param[in] b buffer page -@param[in] ofs byte offset from b->frame -@param[in] len length of the data to write -@param[in] val the data byte to write */ -inline void mtr_t::memset(const buf_block_t &b, ulint ofs, ulint len, byte val) +@param b buffer page +@param ofs byte offset within buffer page frame +@param len length of the data to write +@param val the data byte to write */ +inline void mtr_t::memset(const buf_block_t &b, size_t ofs, size_t len, + byte val) { ut_ad(len); + ut_ad(ofs + len < srv_page_size); set_modified(b); if (!is_logged()) return; @@ -233,33 +234,32 @@ inline void mtr_t::memset(const buf_block_t &b, ulint ofs, ulint len, byte val) l= mlog_encode_varint(l, len); *l++= val; m_log.close(l); - m_last_offset= static_cast(ofs + len); + m_last_offset= uint16_t(ofs + len); } /** Initialize a string of bytes. -@param[in,out] b buffer page -@param[in] ofs byte offset from block->frame -@param[in] len length of the data to write -@param[in] val the data byte to write */ -inline void mtr_t::memset(const buf_block_t *b, ulint ofs, ulint len, byte val) +@param b buffer page +@param ofs byte offset within buffer page frame +@param len length of the data to write +@param val the data byte to write */ +inline void mtr_t::memset(const buf_block_t *b, byte *ofs, ulint len, byte val) { - ut_ad(ofs <= ulint(srv_page_size)); - ut_ad(ofs + len <= ulint(srv_page_size)); - ::memset(ofs + b->page.frame, val, len); - memset(*b, ofs, len, val); + ::memset(ofs, val, len); + memset(*b, ofs - b->page.frame, len, val); } /** Log an initialization of a repeating string of bytes. -@param[in] b buffer page -@param[in] ofs byte offset from b->frame -@param[in] len length of the data to write, in bytes -@param[in] str the string to write -@param[in] size size of str, in bytes */ -inline void mtr_t::memset(const buf_block_t &b, ulint ofs, size_t len, +@param b buffer page +@param ofs byte offset within buffer page frame +@param len length of the data to write, in bytes +@param str the string to write +@param size size of str, in bytes */ +inline void mtr_t::memset(const buf_block_t &b, size_t ofs, size_t len, const void *str, size_t size) { ut_ad(size); ut_ad(len > size); /* use mtr_t::memcpy() for shorter writes */ + ut_ad(ofs + len < srv_page_size); set_modified(b); if (!is_logged()) return; @@ -271,87 +271,75 @@ inline void mtr_t::memset(const buf_block_t &b, ulint ofs, size_t len, ::memcpy(l, str, size); l+= size; m_log.close(l); - m_last_offset= static_cast(ofs + len); + m_last_offset= uint16_t(ofs + len); } /** Initialize a repeating string of bytes. -@param[in,out] b buffer page -@param[in] ofs byte offset from b->frame -@param[in] len length of the data to write, in bytes -@param[in] str the string to write -@param[in] size size of str, in bytes */ -inline void mtr_t::memset(const buf_block_t *b, ulint ofs, size_t len, +@param b buffer page +@param ofs byte offset within buffer page frame +@param len length of the data to write, in bytes +@param str the string to write +@param size size of str, in bytes */ +inline void mtr_t::memset(const buf_block_t *b, byte *ofs, size_t len, const void *str, size_t size) { - ut_ad(ofs <= ulint(srv_page_size)); - ut_ad(ofs + len <= ulint(srv_page_size)); ut_ad(len > size); /* use mtr_t::memcpy() for shorter writes */ size_t s= 0; while (s < len) { - ::memcpy(ofs + s + b->page.frame, str, size); + ::memcpy(ofs + s, str, size); s+= len; } - ::memcpy(ofs + s + b->page.frame, str, len - s); - memset(*b, ofs, len, str, size); -} - -/** Log a write of a byte string to a page. -@param[in] b buffer page -@param[in] offset byte offset from b->frame -@param[in] str the data to write -@param[in] len length of the data to write */ -inline void mtr_t::memcpy(const buf_block_t &b, ulint offset, ulint len) -{ - ut_ad(len); - ut_ad(offset <= ulint(srv_page_size)); - ut_ad(offset + len <= ulint(srv_page_size)); - memcpy_low(b, uint16_t(offset), &b.page.frame[offset], len); + ::memcpy(ofs + s, str, len - s); + memset(*b, ofs - b->page.frame, len, str, size); } /** Log a write of a byte string to a page. @param block page -@param offset byte offset within page -@param data data to be written +@param offset byte offset within page frame @param len length of the data, in bytes */ -inline void mtr_t::memcpy_low(const buf_block_t &block, uint16_t offset, - const void *data, size_t len) +inline void mtr_t::memcpy(const buf_block_t &block, const void *offset, + size_t len) { + ut_ad(ut_align_down(offset, srv_page_size) == block.page.frame); ut_ad(len); set_modified(block); if (!is_logged()) return; + const uint16_t o= + uint16_t(static_cast(offset) - block.page.frame); + ut_ad(o + len <= ulint(srv_page_size)); if (len < mtr_buf_t::MAX_DATA_SIZE - (1 + 3 + 3 + 5 + 5)) { - byte *end= log_write(block.page.id(), &block.page, len, true, - offset); - ::memcpy(end, data, len); + byte *end= log_write(block.page.id(), &block.page, len, true, o); + ::memcpy(end, offset, len); m_log.close(end + len); } else { - m_log.close(log_write(block.page.id(), &block.page, len, false, - offset)); - m_log.push(static_cast(data), static_cast(len)); + m_log.close(log_write(block.page.id(), &block.page, len, false, o)); + m_log.push(static_cast(offset), static_cast(len)); } - m_last_offset= static_cast(offset + len); + m_last_offset= static_cast(o + len); } /** Log that a string of bytes was copied from the same page. -@param[in] b buffer page -@param[in] d destination offset within the page -@param[in] s source offset within the page -@param[in] len length of the data to copy */ -inline void mtr_t::memmove(const buf_block_t &b, ulint d, ulint s, ulint len) +@param b buffer page +@param d destination offset within the page +@param s source offset within the page +@param len length of the data to copy */ +inline void mtr_t::memmove(const buf_block_t &b, const byte *d, const byte *s, + ulint len) { - ut_ad(d >= 8); - ut_ad(s >= 8); ut_ad(len); - ut_ad(s <= ulint(srv_page_size)); - ut_ad(s + len <= ulint(srv_page_size)); ut_ad(s != d); - ut_ad(d <= ulint(srv_page_size)); - ut_ad(d + len <= ulint(srv_page_size)); + ut_d(const byte *frame= b.page.frame); + ut_ad(d >= frame + 8); + ut_ad(s >= frame + 8); + ut_ad(s <= frame + srv_page_size); + ut_ad(d <= frame + srv_page_size); + ut_ad(s + len <= frame + srv_page_size); + ut_ad(d + len <= frame + srv_page_size); set_modified(b); if (!is_logged()) @@ -360,18 +348,16 @@ inline void mtr_t::memmove(const buf_block_t &b, ulint d, ulint s, ulint len) size_t lenlen= (len < MIN_2BYTE ? 1 : len < MIN_3BYTE ? 2 : 3); /* The source offset is encoded relative to the destination offset, with the sign in the least significant bit. */ - if (s > d) - s= (s - d) << 1; - else - s= (d - s) << 1 | 1; + uint16_t S= s > d ? uint16_t((s - d) << 1) : uint16_t((d - s) << 1 | 1); /* The source offset 0 is not possible. */ - s-= 1 << 1; - size_t slen= (s < MIN_2BYTE ? 1 : s < MIN_3BYTE ? 2 : 3); - byte *l= log_write(b.page.id(), &b.page, lenlen + slen, true, d); + S= uint16_t(S - (1U << 1)); + const uint16_t D= uint16_t(d - b.page.frame); + size_t slen= (S < MIN_2BYTE ? 1 : S < MIN_3BYTE ? 2 : 3); + byte *l= log_write(b.page.id(), &b.page, lenlen + slen, true, D); l= mlog_encode_varint(l, len); - l= mlog_encode_varint(l, s); + l= mlog_encode_varint(l, S); m_log.close(l); - m_last_offset= static_cast(d + len); + m_last_offset= uint16_t(D + len); } /** @@ -481,7 +467,7 @@ inline byte *mtr_t::log_write(const page_id_t id, const buf_page_t *bpage, /** Write a byte string to a page. @param[in] b buffer page -@param[in] dest destination within b.frame +@param[in] dest destination within page frame @param[in] str the data to write @param[in] len length of the data to write @tparam w write request type */ @@ -509,7 +495,7 @@ inline void mtr_t::memcpy(const buf_block_t &b, void *dest, const void *str, len= static_cast(end - d); } ::memcpy(d, s, len); - memcpy(b, ut_align_offset(d, srv_page_size), len); + memcpy(b, d, len); } /** Write an EXTENDED log record. diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 3828a31cdb518..fec6459b6e06b 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -469,14 +469,14 @@ struct mtr_t { MY_ATTRIBUTE((nonnull)); /** Log a write of a byte string to a page. - @param[in] b buffer page - @param[in] ofs byte offset from b->frame - @param[in] len length of the data to write */ - inline void memcpy(const buf_block_t &b, ulint ofs, ulint len); + @param block buffer page + @param offset byte offset within page frame + @param len length of the data, in bytes */ + inline void memcpy(const buf_block_t &block, const void *offset, size_t len); /** Write a byte string to a page. @param[in,out] b buffer page - @param[in] dest destination within b.frame + @param[in] dest destination within page frame @param[in] str the data to write @param[in] len length of the data to write @tparam w write request type */ @@ -486,9 +486,9 @@ struct mtr_t { /** Log a write of a byte string to a ROW_FORMAT=COMPRESSED page. @param[in] b ROW_FORMAT=COMPRESSED index page - @param[in] offset byte offset from b.zip.data + @param[in] offset offset within b.page.zip.data @param[in] len length of the data to write */ - inline void zmemcpy(const buf_block_t &b, ulint offset, ulint len); + void zmemcpy(const buf_block_t &b, const byte *offset, ulint len); /** Write a byte string to a ROW_FORMAT=COMPRESSED page. @param[in] b ROW_FORMAT=COMPRESSED index page @@ -497,47 +497,63 @@ struct mtr_t { @param[in] len length of the data to write @tparam w write request type */ template - inline void zmemcpy(const buf_block_t &b, void *dest, const void *str, - ulint len); + void zmemcpy(const buf_block_t &b, void *dest, const void *str, ulint len); /** Log an initialization of a string of bytes. - @param[in] b buffer page - @param[in] ofs byte offset from b->frame - @param[in] len length of the data to write - @param[in] val the data byte to write */ - inline void memset(const buf_block_t &b, ulint ofs, ulint len, byte val); + @param b buffer page + @param ofs byte offset within buffer page frame + @param len length of the data to write + @param val the data byte to write */ + inline void memset(const buf_block_t &b, size_t ofs, size_t len, byte val); /** Initialize a string of bytes. - @param[in,out] b buffer page - @param[in] ofs byte offset from b->frame - @param[in] len length of the data to write - @param[in] val the data byte to write */ - inline void memset(const buf_block_t *b, ulint ofs, ulint len, byte val); + @param b buffer page + @param ofs byte offset within buffer page frame + @param len length of the data to write + @param val the data byte to write */ + inline void memset(const buf_block_t *b, byte *ofs, ulint len, byte val); /** Log an initialization of a repeating string of bytes. - @param[in] b buffer page - @param[in] ofs byte offset from b->frame - @param[in] len length of the data to write, in bytes - @param[in] str the string to write - @param[in] size size of str, in bytes */ - inline void memset(const buf_block_t &b, ulint ofs, size_t len, + @param b buffer page + @param ofs byte offset within buffer page frame + @param len length of the data to write, in bytes + @param str the string to write + @param size size of str, in bytes */ + inline void memset(const buf_block_t &b, size_t ofs, size_t len, const void *str, size_t size); /** Initialize a repeating string of bytes. - @param[in,out] b buffer page - @param[in] ofs byte offset from b->frame - @param[in] len length of the data to write, in bytes - @param[in] str the string to write - @param[in] size size of str, in bytes */ - inline void memset(const buf_block_t *b, ulint ofs, size_t len, + @param b buffer page + @param ofs byte offset within buffer page frame + @param len length of the data to write, in bytes + @param str the string to write + @param size size of str, in bytes */ + inline void memset(const buf_block_t *b, byte *ofs, size_t len, const void *str, size_t size); /** Log that a string of bytes was copied from the same page. - @param[in] b buffer page - @param[in] d destination offset within the page - @param[in] s source offset within the page - @param[in] len length of the data to copy */ - inline void memmove(const buf_block_t &b, ulint d, ulint s, ulint len); + @param b buffer page + @param d destination offset within the page + @param s source offset within the page + @param len length of the data to copy */ + inline void memmove(const buf_block_t &b, const byte *d, const byte *s, + size_t len); + + /** Log that a string of bytes was copied from the same + ROW_FORMAT=COMPRESSED page. + @param b buffer page + @param d destination offset within the page + @param s source offset within the page + @param len length of the data to copy */ + void zmemmove(const buf_block_t &b, const byte *d, const byte *s, + size_t len); + + /** Log an initialization of a string of bytes. + @param b ROW_FORMAT=COMPRESSED buffer page + @param ofs byte offset within the compressed buffer page frame + @param len length of the data to write + @param val the data byte to write */ + void zmemset(const buf_block_t &b, const byte *ofs, size_t len, byte val); /** Initialize an entire page. @param[in,out] b buffer page */ @@ -657,13 +673,6 @@ struct mtr_t { }; private: - /** Log a write of a byte string to a page. - @param block buffer page - @param offset byte offset within page - @param data data to be written - @param len length of the data, in bytes */ - inline void memcpy_low(const buf_block_t &block, uint16_t offset, - const void *data, size_t len); /** Write a log record. @tparam type redo log record type diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h index 28aa30565e46a..d4f7c69af2ad3 100644 --- a/storage/innobase/include/page0cur.h +++ b/storage/innobase/include/page0cur.h @@ -31,14 +31,6 @@ Created 10/4/1994 Heikki Tuuri #ifdef UNIV_DEBUG /*********************************************************//** -Gets pointer to the page frame where the cursor is positioned. -@return page */ -UNIV_INLINE -page_t* -page_cur_get_page( -/*==============*/ - page_cur_t* cur); /*!< in: page cursor */ -/*********************************************************//** Gets pointer to the buffer block where the cursor is positioned. @return page */ UNIV_INLINE @@ -60,12 +52,20 @@ page_cur_get_page_zip( UNIV_INLINE rec_t *page_cur_get_rec(const page_cur_t *cur); #else /* UNIV_DEBUG */ -# define page_cur_get_page(cur) page_align((cur)->rec) # define page_cur_get_block(cur) (cur)->block # define page_cur_get_page_zip(cur) buf_block_get_page_zip((cur)->block) # define page_cur_get_rec(cur) (cur)->rec #endif /* UNIV_DEBUG */ +# define page_cur_get_page(cur) (cur)->block->page.frame # define is_page_cur_get_page_zip(cur) is_buf_block_get_page_zip((cur)->block) + +/** Looks for the directory slot which owns the given record. +@param page index page +@param rec index record +@return the directory slot number +@retval ULINT_UNDEFINED on corruption */ +ulint page_dir_find_owner_slot(const page_t *page, const rec_t *rec); + /*********************************************************//** Sets the cursor object to point before the first user record on the page. */ @@ -271,10 +271,6 @@ page_cur_search_with_match_bytes( ulint* ilow_matched_bytes, page_cur_t* cursor); #endif /* BTR_CUR_HASH_ADAPT */ -/***********************************************************//** -Positions a page cursor on a randomly chosen user record on a page. If there -are no user records, sets the cursor on the infimum record. */ -void page_cur_open_on_rnd_user_rec(page_cur_t *cursor); /** Index page cursor */ @@ -289,13 +285,13 @@ struct page_cur_t{ MY_ATTRIBUTE((nonnull, warn_unused_result)) inline rec_t *page_cur_move_to_next(page_cur_t *cur) { - return cur->rec= page_rec_get_next(cur->rec); + return cur->rec= page_rec_get_next(cur->block->page.frame, cur->rec); } MY_ATTRIBUTE((nonnull, warn_unused_result)) inline rec_t *page_cur_move_to_prev(page_cur_t *cur) { - return cur->rec= page_rec_get_prev(cur->rec); + return cur->rec= page_rec_get_prev(cur->block->page.frame, cur->rec); } #include "page0cur.inl" diff --git a/storage/innobase/include/page0cur.inl b/storage/innobase/include/page0cur.inl index 1638b5749ff4a..2dc695ed42262 100644 --- a/storage/innobase/include/page0cur.inl +++ b/storage/innobase/include/page0cur.inl @@ -25,18 +25,6 @@ Created 10/4/1994 Heikki Tuuri *************************************************************************/ #ifdef UNIV_DEBUG -/*********************************************************//** -Gets pointer to the page frame where the cursor is positioned. -@return page */ -UNIV_INLINE -page_t* -page_cur_get_page( -/*==============*/ - page_cur_t* cur) /*!< in: page cursor */ -{ - return page_align(page_cur_get_rec(cur)); -} - /*********************************************************//** Gets pointer to the buffer block where the cursor is positioned. @return page */ @@ -86,7 +74,7 @@ page_cur_set_before_first( page_cur_t* cur) /*!< in: cursor */ { cur->block = const_cast(block); - cur->rec = page_get_infimum_rec(buf_block_get_frame(cur->block)); + cur->rec = page_get_infimum_rec(block->page.frame); } /*********************************************************//** @@ -100,7 +88,7 @@ page_cur_set_after_last( page_cur_t* cur) /*!< in: cursor */ { cur->block = const_cast(block); - cur->rec = page_get_supremum_rec(buf_block_get_frame(cur->block)); + cur->rec = page_get_supremum_rec(block->page.frame); } /*********************************************************//** @@ -112,9 +100,7 @@ page_cur_is_before_first( /*=====================*/ const page_cur_t* cur) /*!< in: cursor */ { - ut_ad(cur); - ut_ad(page_align(cur->rec) == cur->block->page.frame); - return(page_rec_is_infimum(cur->rec)); + return page_rec_is_infimum(cur->block->page.frame, cur->rec); } /*********************************************************//** @@ -126,9 +112,7 @@ page_cur_is_after_last( /*===================*/ const page_cur_t* cur) /*!< in: cursor */ { - ut_ad(cur); - ut_ad(page_align(cur->rec) == cur->block->page.frame); - return(page_rec_is_supremum(cur->rec)); + return page_rec_is_supremum(cur->block->page.frame, cur->rec); } /**********************************************************//** diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 0ad42474f8463..f6c31134fb273 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -202,6 +202,8 @@ inline page_t* page_align(void *ptr) return my_assume_aligned (reinterpret_cast(ut_align_down(ptr, srv_page_size))); } + +MY_ATTRIBUTE((const)) inline const page_t *page_align(const void *ptr) { return page_align(const_cast(ptr)); @@ -216,6 +218,24 @@ inline uint16_t page_offset(const void* ptr) return static_cast(ut_align_offset(ptr, srv_page_size)); } +/** Read a page header field. */ +inline uint16_t page_header_get_field(const page_t *page, ulint field) +{ + ut_ad(field <= PAGE_INDEX_ID); + ut_ad(!(field & 1)); + return mach_read_from_2(my_assume_aligned<2>(PAGE_HEADER + field + page)); +} + +/** Check the consistency of a record */ +MY_ATTRIBUTE((nonnull, warn_unused_result)) +inline bool page_rec_check(const page_t *page, const rec_t *rec) +{ + auto offset= rec - page; + return offset >= PAGE_DATA && + offset <= page_header_get_field(page, PAGE_HEAP_TOP); +} + + /** Determine whether an index page is not in ROW_FORMAT=REDUNDANT. @param[in] page index page @return nonzero if ROW_FORMAT is one of COMPACT,DYNAMIC,COMPRESSED @@ -374,25 +394,37 @@ page_rec_is_leaf(const page_t* rec) } /** Determine whether an index page record is a user record. -@param[in] rec record in an index page +@param page index page +@param rec record in the page @return true if a user record */ -inline -bool -page_rec_is_user_rec(const rec_t* rec); +inline bool page_rec_is_user_rec(const page_t *page, const rec_t *rec) +{ + ut_ad(page == page_align(rec)); + ut_ad(page_rec_check(page, rec)); + return page_rec_is_user_rec_low(rec - page); +} /** Determine whether an index page record is the supremum record. -@param[in] rec record in an index page +@param page index page +@param rec record in the page @return true if the supremum record */ -inline -bool -page_rec_is_supremum(const rec_t* rec); +inline bool page_rec_is_supremum(const page_t *page, const rec_t *rec) +{ + ut_ad(page == page_align(rec)); + ut_ad(page_rec_check(page, rec)); + return page_rec_is_supremum_low(rec - page); +} /** Determine whether an index page record is the infimum record. -@param[in] rec record in an index page +@param page index page +@param rec record in the page @return true if the infimum record */ -inline -bool -page_rec_is_infimum(const rec_t* rec); +inline bool page_rec_is_infimum(const page_t *page, const rec_t *rec) +{ + ut_ad(page == page_align(rec)); + ut_ad(page_rec_check(page, rec)); + return page_rec_is_infimum_low(rec - page); +} /** Read PAGE_MAX_TRX_ID. @param[in] page index page @@ -410,7 +442,7 @@ inline trx_id_t page_get_max_trx_id(const page_t *page) Set the number of owned records. @tparam compressed whether to update any ROW_FORMAT=COMPRESSED page as well @param[in,out] block index page -@param[in,out] rec record in block.frame +@param[in,out] rec record in block->page.frame @param[in] n_owned number of records skipped in the sparse page directory @param[in] comp whether ROW_FORMAT is one of COMPACT,DYNAMIC,COMPRESSED @param[in,out] mtr mini-transaction */ @@ -419,7 +451,7 @@ inline void page_rec_set_n_owned(buf_block_t *block, rec_t *rec, ulint n_owned, bool comp, mtr_t *mtr) { ut_ad(block->page.frame == page_align(rec)); - ut_ad(comp == (page_is_comp(block->page.frame) != 0)); + ut_ad(comp == (page_rec_is_comp(rec) != 0)); if (page_zip_des_t *page_zip= compressed ? buf_block_get_page_zip(block) : nullptr) @@ -444,6 +476,7 @@ void page_set_max_trx_id( /*================*/ buf_block_t* block, /*!< in/out: page */ + page_t* page, /*!< in/out: page frame */ page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ trx_id_t trx_id, /*!< in: transaction id */ mtr_t* mtr); /*!< in/out: mini-transaction, or NULL */ @@ -496,14 +529,6 @@ page_set_ssn_id( mtr_t* mtr); /*!< in/out: mini-transaction */ #endif /* !UNIV_INNOCHECKSUM */ -/** Read a page header field. */ -inline uint16_t page_header_get_field(const page_t *page, ulint field) -{ - ut_ad(field <= PAGE_INDEX_ID); - ut_ad(!(field & 1)); - return mach_read_from_2(my_assume_aligned<2>(PAGE_HEADER + field + page)); -} - #ifndef UNIV_INNOCHECKSUM /*************************************************************//** Returns the offset stored in the given header field. @@ -525,8 +550,10 @@ Returns the pointer stored in the given header field, or NULL. */ /** Reset PAGE_LAST_INSERT. @param[in,out] block file page +@param[in,out] page file page frame @param[in,out] mtr mini-transaction */ -inline void page_header_reset_last_insert(buf_block_t *block, mtr_t *mtr) +inline void page_header_reset_last_insert(buf_block_t *block, page_t *page, + mtr_t *mtr) MY_ATTRIBUTE((nonnull)); #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) @@ -592,10 +619,11 @@ page_get_n_recs( const page_t* page); /*!< in: index page */ /** Return the number of preceding records in an index page. -@param rec index record +@param page index page +@param rec index record @return number of preceding records, including the infimum pseudo-record @retval ULINT_UNDEFINED on corrupted page */ -ulint page_rec_get_n_recs_before(const rec_t *rec); +ulint page_rec_get_n_recs_before(const page_t *page, const rec_t *rec); /*************************************************************//** Gets the number of records in the heap. @return number of user records */ @@ -625,50 +653,54 @@ inline const page_dir_slot_t *page_dir_get_nth_slot(const page_t *page,ulint n) { return page_dir_get_nth_slot(const_cast(page), n); } -/**************************************************************//** -Used to check the consistency of a record on a page. -@return TRUE if succeed */ -UNIV_INLINE -ibool -page_rec_check( -/*===========*/ - const rec_t* rec); /*!< in: record */ + /** Get the record pointed to by a directory slot. -@param[in] slot directory slot +@param page index page +@param slot directory slot @return pointer to record */ -inline rec_t *page_dir_slot_get_rec(page_dir_slot_t *slot) +inline rec_t *page_dir_slot_get_rec(page_t *page, + const page_dir_slot_t *slot) { - return page_align(slot) + mach_read_from_2(my_assume_aligned<2>(slot)); + ut_ad(page == page_align(slot)); + return page + mach_read_from_2(my_assume_aligned<2>(slot)); } -inline const rec_t *page_dir_slot_get_rec(const page_dir_slot_t *slot) +inline const rec_t *page_dir_slot_get_rec(const page_t *page, + const page_dir_slot_t *slot) { - return page_dir_slot_get_rec(const_cast(slot)); + return page_dir_slot_get_rec(const_cast(page), slot); } -inline rec_t *page_dir_slot_get_rec_validate(page_dir_slot_t *slot) +inline rec_t *page_dir_slot_get_rec_validate(page_t *page, + const page_dir_slot_t *slot) { const size_t s= mach_read_from_2(my_assume_aligned<2>(slot)); - page_t *page= page_align(slot); + ut_ad(page == page_align(slot)); return UNIV_LIKELY(s >= PAGE_NEW_INFIMUM && s <= page_header_get_field(page, PAGE_HEAP_TOP)) ? page + s : nullptr; } -inline const rec_t *page_dir_slot_get_rec_validate(const page_dir_slot_t *slot) +inline const rec_t *page_dir_slot_get_rec_validate(const page_t *page, + const page_dir_slot_t *slot) { - return page_dir_slot_get_rec_validate(const_cast(slot)); + return page_dir_slot_get_rec_validate(const_cast(page), slot); } -/***************************************************************//** -Gets the number of records owned by a directory slot. +/** Determine the number of records owned by a directory slot. +@param page index page +@param slot directory slot @return number of records */ -UNIV_INLINE -ulint -page_dir_slot_get_n_owned( -/*======================*/ - const page_dir_slot_t* slot); /*!< in: page directory slot */ +inline ulint page_dir_slot_get_n_owned(const page_t *page, + const page_dir_slot_t *slot) +{ + const rec_t *rec= page_dir_slot_get_rec(page, slot); + return page_is_comp(page) + ? rec_get_n_owned_new(rec) + : rec_get_n_owned_old(rec); +} + /************************************************************//** Calculates the space reserved for directory slots of a given number of records. The exact value is a fraction number @@ -679,23 +711,19 @@ ulint page_dir_calc_reserved_space( /*=========================*/ ulint n_recs); /*!< in: number of records */ -/***************************************************************//** -Looks for the directory slot which owns the given record. -@return the directory slot number -@retval ULINT_UNDEFINED on corruption */ -ulint -page_dir_find_owner_slot( -/*=====================*/ - const rec_t* rec); /*!< in: the physical record */ -/***************************************************************//** -Returns the heap number of a record. +/** Determine the heap number of a record. +@param page index page +@param rec record in the page @return heap number */ -UNIV_INLINE -ulint -page_rec_get_heap_no( -/*=================*/ - const rec_t* rec); /*!< in: the physical record */ +inline ulint page_rec_get_heap_no(const page_t *page, const rec_t *rec) +{ + ut_ad(page == page_align(rec)); + return page_is_comp(page) + ? rec_get_heap_no_new(rec) + : rec_get_heap_no_old(rec); +} + /** Determine whether a page has any siblings. @param[in] page page frame @return true if the page has any siblings */ @@ -739,71 +767,80 @@ inline uint64_t page_get_autoinc(const page_t *page) return mach_read_from_8(p); } -/************************************************************//** -Gets the pointer to the next record on the page. +/** Get the next record on a page. +@param page index page +@param rec record in the page +@param comp not ROW_FORMAT=REDUNDANT @return pointer to next record */ -UNIV_INLINE -const rec_t* -page_rec_get_next_low( -/*==================*/ - const rec_t* rec, /*!< in: pointer to record */ - ulint comp); /*!< in: nonzero=compact page layout */ -/************************************************************//** -Gets the pointer to the next record on the page. -@return pointer to next record */ -UNIV_INLINE -rec_t* -page_rec_get_next( -/*==============*/ - rec_t* rec); /*!< in: pointer to record */ -/************************************************************//** -Gets the pointer to the next record on the page. +inline rec_t *page_rec_get_next_low(page_t *page, const rec_t *rec, ulint comp) +{ + ut_ad(page == page_align(rec)); + ut_ad(page_rec_check(page, rec)); + ulint offs= rec_get_next_offs(rec, comp); + if (!offs) + return nullptr; + if (UNIV_UNLIKELY(offs < (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM))) + return nullptr; + if (UNIV_UNLIKELY(offs > page_header_get_field(page, PAGE_HEAP_TOP))) + return nullptr; + ut_ad(page_rec_is_infimum(page, rec) || + (!page_is_leaf(page) && !page_has_prev(page)) || + !(rec_get_info_bits(page + offs, comp) & REC_INFO_MIN_REC_FLAG)); + return page + offs; +} +inline const rec_t *page_rec_get_next_low(const page_t *page, const rec_t *rec, + ulint comp) +{ + return page_rec_get_next_low(const_cast(page), rec, comp); +} + +/** Get the next record on a page. +@param page index page +@param rec record in the page @return pointer to next record */ -UNIV_INLINE -const rec_t* -page_rec_get_next_const( -/*====================*/ - const rec_t* rec); /*!< in: pointer to record */ -/************************************************************//** -Gets the pointer to the previous record. -@return pointer to previous record -@retval nullptr on error */ -const rec_t* -page_rec_get_prev_const( -/*====================*/ - const rec_t* rec); /*!< in: pointer to record, must not be page - infimum */ -/************************************************************//** -Gets the pointer to the previous record. -@param rec record (not page infimum) +inline rec_t *page_rec_get_next(page_t *page, const rec_t *rec) +{ + return page_rec_get_next_low(page, rec, page_is_comp(page)); +} +inline const rec_t* page_rec_get_next(const page_t *page, const rec_t *rec) +{ + return page_rec_get_next(const_cast(page), rec); +} + +/** Get the previous record on a page. +@param page index page +@param rec record in the page (not page infimum) @return pointer to previous record @retval nullptr on error */ -inline rec_t *page_rec_get_prev(rec_t *rec) +rec_t *page_rec_get_prev(page_t *page, const rec_t *rec); +inline const rec_t *page_rec_get_prev(const page_t *page, const rec_t *rec) { - return const_cast(page_rec_get_prev_const(rec)); + return page_rec_get_prev(const_cast(page), rec); } -/************************************************************//** -true if the record is the first user record on a page. -@return true if the first user record */ -UNIV_INLINE -bool -page_rec_is_first( -/*==============*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ - MY_ATTRIBUTE((warn_unused_result)); +/** Get the first record on a page. +@param page index page +@return first record (or page supremum) */ +inline rec_t *page_rec_get_first(page_t *page) +{ + return page_rec_get_next(page, page_get_infimum_rec(page)); +} +inline const rec_t *page_rec_get_first(const page_t *page) +{ + return page_rec_get_first(const_cast(page)); +} -/************************************************************//** -true if the record is the last user record on a page. -@return true if the last user record */ -UNIV_INLINE -bool -page_rec_is_last( -/*=============*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ - MY_ATTRIBUTE((warn_unused_result)); +inline bool page_rec_is_first(const page_t *page, const rec_t *rec) +{ + ut_ad(page_get_n_recs(page) > 0); + return page_rec_get_first(page) == rec; +} + +inline bool page_rec_is_last(const page_t *page, const rec_t *rec) +{ + ut_ad(page_get_n_recs(page) > 0); + return page_rec_get_next(page, rec) == page_get_supremum_rec(page); +} /************************************************************//** Returns the maximum combined size of records which can be inserted on top @@ -870,8 +907,9 @@ page_get_instant(const page_t* page); /** Create an uncompressed index page. @param[in,out] block buffer block @param[in,out] mtr mini-transaction -@param[in] comp set unless ROW_FORMAT=REDUNDANT */ -void page_create(buf_block_t *block, mtr_t *mtr, bool comp); +@param[in] comp set unless ROW_FORMAT=REDUNDANT +@return page frame */ +page_t *page_create(buf_block_t *block, mtr_t *mtr, bool comp); /**********************************************************//** Create a compressed B-tree index page. */ void @@ -892,6 +930,7 @@ void page_create_empty( /*==============*/ buf_block_t* block, /*!< in/out: B-tree block */ + page_t* page, /*!< in: block page frame */ dict_index_t* index, /*!< in: the index of the page */ mtr_t* mtr) /*!< in/out: mini-transaction */ MY_ATTRIBUTE((nonnull(1,2))); @@ -988,8 +1027,9 @@ page_delete_rec_list_start( MY_ATTRIBUTE((nonnull)); /** Create an index page. @param[in,out] block buffer block -@param[in] comp nonzero=compact page format */ -void page_create_low(const buf_block_t* block, bool comp); +@param[in] comp nonzero=compact page format +@return page frame */ +page_t *page_create_low(const buf_block_t* block, bool comp); /************************************************************//** Prints record contents including the data relevant only in diff --git a/storage/innobase/include/page0page.inl b/storage/innobase/include/page0page.inl index 6c0167edcf9ba..cd35cb49a638b 100644 --- a/storage/innobase/include/page0page.inl +++ b/storage/innobase/include/page0page.inl @@ -45,11 +45,11 @@ page_update_max_trx_id( ut_ad(block); ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); ut_ad(trx_id); - ut_ad(page_is_leaf(buf_block_get_frame(block))); + page_t* page = block->page.frame; + ut_ad(page_is_leaf(page)); - if (page_get_max_trx_id(buf_block_get_frame(block)) < trx_id) { - - page_set_max_trx_id(block, page_zip, trx_id, mtr); + if (page_get_max_trx_id(page) < trx_id) { + page_set_max_trx_id(block, page, page_zip, trx_id, mtr); } } @@ -118,95 +118,18 @@ page_header_get_offs( /** Reset PAGE_LAST_INSERT. @param[in,out] block file page +@param[in,out] page file page frame @param[in,out] mtr mini-transaction */ -inline void page_header_reset_last_insert(buf_block_t *block, mtr_t *mtr) +inline void page_header_reset_last_insert(buf_block_t *block, page_t *page, + mtr_t *mtr) { constexpr uint16_t field= PAGE_HEADER + PAGE_LAST_INSERT; - byte *b= my_assume_aligned<2>(&block->page.frame[field]); + byte *b= my_assume_aligned<2>(&page[field]); if (mtr->write<2,mtr_t::MAYBE_NOP>(*block, b, 0U) && UNIV_LIKELY_NULL(block->page.zip.data)) memset_aligned<2>(&block->page.zip.data[field], 0, 2); } -/***************************************************************//** -Returns the heap number of a record. -@return heap number */ -UNIV_INLINE -ulint -page_rec_get_heap_no( -/*=================*/ - const rec_t* rec) /*!< in: the physical record */ -{ - if (page_rec_is_comp(rec)) { - return(rec_get_heap_no_new(rec)); - } else { - return(rec_get_heap_no_old(rec)); - } -} - -/** Determine whether an index page record is a user record. -@param[in] rec record in an index page -@return true if a user record */ -inline -bool -page_rec_is_user_rec(const rec_t* rec) -{ - ut_ad(page_rec_check(rec)); - return(page_rec_is_user_rec_low(page_offset(rec))); -} - -/** Determine whether an index page record is the supremum record. -@param[in] rec record in an index page -@return true if the supremum record */ -inline -bool -page_rec_is_supremum(const rec_t* rec) -{ - ut_ad(page_rec_check(rec)); - return(page_rec_is_supremum_low(page_offset(rec))); -} - -/** Determine whether an index page record is the infimum record. -@param[in] rec record in an index page -@return true if the infimum record */ -inline -bool -page_rec_is_infimum(const rec_t* rec) -{ - ut_ad(page_rec_check(rec)); - return(page_rec_is_infimum_low(page_offset(rec))); -} - -/************************************************************//** -true if the record is the first user record on a page. -@return true if the first user record */ -UNIV_INLINE -bool -page_rec_is_first( -/*==============*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ -{ - ut_ad(page_get_n_recs(page) > 0); - - return(page_rec_get_next_const(page_get_infimum_rec(page)) == rec); -} - -/************************************************************//** -true if the record is the last user record on a page. -@return true if the last user record */ -UNIV_INLINE -bool -page_rec_is_last( -/*=============*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ -{ - ut_ad(page_get_n_recs(page) > 0); - - return(page_rec_get_next_const(rec) == page_get_supremum_rec(page)); -} - /************************************************************//** Returns the middle record of the records on the page. If there is an even number of records in the list, returns the first record of the @@ -294,42 +217,6 @@ page_dir_get_n_heap( return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff); } -/**************************************************************//** -Used to check the consistency of a record on a page. -@return TRUE if succeed */ -UNIV_INLINE -ibool -page_rec_check( -/*===========*/ - const rec_t* rec) /*!< in: record */ -{ - const page_t* page = page_align(rec); - - ut_a(rec); - - ut_a(page_offset(rec) <= page_header_get_field(page, PAGE_HEAP_TOP)); - ut_a(page_offset(rec) >= PAGE_DATA); - - return(TRUE); -} - -/***************************************************************//** -Gets the number of records owned by a directory slot. -@return number of records */ -UNIV_INLINE -ulint -page_dir_slot_get_n_owned( -/*======================*/ - const page_dir_slot_t* slot) /*!< in: page directory slot */ -{ - const rec_t* rec = page_dir_slot_get_rec(slot); - if (page_rec_is_comp(slot)) { - return(rec_get_n_owned_new(rec)); - } else { - return(rec_get_n_owned_old(rec)); - } -} - /************************************************************//** Calculates the space reserved for directory slots of a given number of records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE / @@ -344,54 +231,6 @@ page_dir_calc_reserved_space( / PAGE_DIR_SLOT_MIN_N_OWNED); } -/************************************************************//** -Gets the pointer to the next record on the page. -@return pointer to next record */ -UNIV_INLINE -const rec_t* -page_rec_get_next_low( -/*==================*/ - const rec_t* rec, /*!< in: pointer to record */ - ulint comp) /*!< in: nonzero=compact page layout */ -{ - const page_t *page= page_align(rec); - ut_ad(page_rec_check(rec)); - ulint offs= rec_get_next_offs(rec, comp); - if (!offs) - return nullptr; - if (UNIV_UNLIKELY(offs < (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM))) - return nullptr; - if (UNIV_UNLIKELY(offs > page_header_get_field(page, PAGE_HEAP_TOP))) - return nullptr; - ut_ad(page_rec_is_infimum(rec) || - (!page_is_leaf(page) && !page_has_prev(page)) || - !(rec_get_info_bits(page + offs, comp) & REC_INFO_MIN_REC_FLAG)); - return page + offs; -} - -/************************************************************//** -Gets the pointer to the next record on the page. -@return pointer to next record */ -UNIV_INLINE -rec_t* -page_rec_get_next( -/*==============*/ - rec_t* rec) /*!< in: pointer to record */ -{ - return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec))); -} - -/************************************************************//** -Gets the pointer to the next record on the page. -@return pointer to next record */ -UNIV_INLINE -const rec_t* -page_rec_get_next_const( -/*====================*/ - const rec_t* rec) /*!< in: pointer to record */ -{ - return(page_rec_get_next_low(rec, page_rec_is_comp(rec))); -} #endif /* UNIV_INNOCHECKSUM */ /************************************************************//** diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index 24ba845271d33..c9b15d655fceb 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -251,12 +251,14 @@ If no binlog information is present, the first byte is NUL. */ # include "trx0xa.h" /** Update the WSREP XID information in rollback segment header. -@param[in,out] rseg_header rollback segment header -@param[in] xid WSREP XID -@param[in,out] mtr mini-transaction */ +@param[in,out] rseg_header rollback segment header +@param[in,out] rseg_header_page rollback segment header page frame +@param[in] xid WSREP XID +@param[in,out] mtr mini-transaction */ void trx_rseg_update_wsrep_checkpoint( buf_block_t* rseg_header, + page_t* rseg_header_page, const XID* xid, mtr_t* mtr); @@ -278,24 +280,16 @@ bool trx_rseg_read_wsrep_checkpoint(XID& xid); /** Read the page number of an undo log slot. @param[in] rseg_header rollback segment header @param[in] n slot number */ -inline uint32_t trx_rsegf_get_nth_undo(const buf_block_t *rseg_header, ulint n) +inline uint32_t trx_rsegf_get_nth_undo(const page_t *rseg_header, ulint n) { ut_ad(n < TRX_RSEG_N_SLOTS); return mach_read_from_4(TRX_RSEG + TRX_RSEG_UNDO_SLOTS + - n * TRX_RSEG_SLOT_SIZE + rseg_header->page.frame); + n * TRX_RSEG_SLOT_SIZE + rseg_header); } /** Upgrade a rollback segment header page to MariaDB 10.3 format. -@param[in,out] rseg_header rollback segment header page -@param[in,out] mtr mini-transaction */ -void trx_rseg_format_upgrade(buf_block_t *rseg_header, mtr_t *mtr); - -/** Update the offset information about the end of the binlog entry -which corresponds to the transaction just being committed. -In a replication slave, this updates the master binlog position -up to which replication has proceeded. -@param[in,out] rseg_header rollback segment header -@param[in] trx committing transaction -@param[in,out] mtr mini-transaction */ -void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, const trx_t *trx, - mtr_t *mtr); +@param rseg_header rollback segment header page +@param rseg_header_page rollback segment header page frame +@param mtr mini-transaction */ +void trx_rseg_format_upgrade(buf_block_t *rseg_header, + page_t *rseg_header_page, mtr_t *mtr); diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index fc2564336f9ca..c3c0fab20bc04 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -54,12 +54,6 @@ inline bool trx_sys_hdr_page(const page_id_t page_id) Creates and initializes the transaction system at the database creation. */ dberr_t trx_sys_create_sys_pages(mtr_t *mtr); -/** Find an available rollback segment. -@param[in] sys_header -@return an unallocated rollback segment slot in the TRX_SYS header -@retval ULINT_UNDEFINED if not found */ -ulint -trx_sys_rseg_find_free(const buf_block_t* sys_header); /** Request the TRX_SYS page. @param[in] rw whether to lock the page for writing @return the TRX_SYS page @@ -166,12 +160,12 @@ MySQL/InnoDB 5.1.7, this is FIL_NULL if the slot is unused */ @return undo tablespace id */ inline uint32_t -trx_sysf_rseg_get_space(const buf_block_t* sys_header, ulint rseg_id) +trx_sysf_rseg_get_space(const page_t* sys_header, ulint rseg_id) { ut_ad(rseg_id < TRX_SYS_N_RSEGS); return mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_SPACE + rseg_id * TRX_SYS_RSEG_SLOT_SIZE - + sys_header->page.frame); + + sys_header); } /** Read the page number of a rollback segment slot. @@ -179,12 +173,11 @@ trx_sysf_rseg_get_space(const buf_block_t* sys_header, ulint rseg_id) @param[in] rseg_id rollback segment identifier @return undo page number */ inline uint32_t -trx_sysf_rseg_get_page_no(const buf_block_t *sys_header, ulint rseg_id) +trx_sysf_rseg_get_page_no(const page_t *sys_header, ulint rseg_id) { ut_ad(rseg_id < TRX_SYS_N_RSEGS); return mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_PAGE_NO + - rseg_id * TRX_SYS_RSEG_SLOT_SIZE + - sys_header->page.frame); + rseg_id * TRX_SYS_RSEG_SLOT_SIZE + sys_header); } /** Maximum length of MySQL binlog file name, in bytes. diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index 3d22a33e7807d..ec21c759943aa 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -98,23 +98,23 @@ inline roll_ptr_t trx_read_roll_ptr(const byte* ptr) /** Get the next record in an undo log. @param[in] undo_page undo log page -@param[in] rec undo record offset in the page +@param[in] rec undo record in the page @param[in] page_no undo log header page number @param[in] offset undo log header offset on page @return undo log record, the page latched, NULL if none */ inline trx_undo_rec_t* -trx_undo_page_get_next_rec(const buf_block_t *undo_page, uint16_t rec, +trx_undo_page_get_next_rec(const buf_block_t *undo_page, const byte *rec, uint32_t page_no, uint16_t offset); /** Get the previous record in an undo log. @param[in,out] block undo log page -@param[in] rec undo record offset in the page +@param[in] rec undo record in the page @param[in] page_no undo log header page number @param[in] offset undo log header offset on page @param[in] shared latching mode: true=RW_S_LATCH, false=RW_X_LATCH @param[in,out] mtr mini-transaction @return undo log record, the page latched, NULL if none */ trx_undo_rec_t* -trx_undo_get_prev_rec(buf_block_t *&block, uint16_t rec, uint32_t page_no, +trx_undo_get_prev_rec(buf_block_t *&block, const byte *rec, uint32_t page_no, uint16_t offset, bool shared, mtr_t *mtr); /** Get the first undo log record on a page. @@ -125,13 +125,14 @@ trx_undo_get_prev_rec(buf_block_t *&block, uint16_t rec, uint32_t page_no, @retval nullptr if none exists */ trx_undo_rec_t* trx_undo_page_get_first_rec(const buf_block_t *block, uint32_t page_no, - uint16_t offset); + const byte *offset); /** Initialize an undo log page. NOTE: This corresponds to a redo log record and must not be changed! @see mtr_t::undo_create() -@param[in,out] block undo log page */ -void trx_undo_page_init(const buf_block_t &block); +@param block undo log page +@param page undo log page frame */ +void trx_undo_page_init(const buf_block_t &block, page_t *page); /** Allocate an undo log page. @param[in,out] undo undo log diff --git a/storage/innobase/include/trx0undo.inl b/storage/innobase/include/trx0undo.inl index 023e2b98fb2c4..6f0fec7bc93f9 100644 --- a/storage/innobase/include/trx0undo.inl +++ b/storage/innobase/include/trx0undo.inl @@ -101,30 +101,30 @@ trx_undo_trx_id_is_insert( @param[in] offset undo log header offset @return end offset */ inline -uint16_t trx_undo_page_get_end(const buf_block_t *undo_page, uint32_t page_no, - uint16_t offset) +uint16_t trx_undo_page_get_end(const buf_block_t *undo_page, + uint32_t page_no, const byte *offset) { if (page_no == undo_page->page.id().page_no()) - if (uint16_t end = mach_read_from_2(TRX_UNDO_NEXT_LOG + offset + - undo_page->page.frame)) + if (uint16_t end = mach_read_from_2(TRX_UNDO_NEXT_LOG + offset)) return end; return mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + - undo_page->page.frame); + undo_page->page.frame); } /** Get the next record in an undo log. @param[in] undo_page undo log page -@param[in] rec undo record offset in the page +@param[in] rec undo record in the page @param[in] page_no undo log header page number @param[in] offset undo log header offset on page @return undo log record, the page latched, NULL if none */ inline trx_undo_rec_t* -trx_undo_page_get_next_rec(const buf_block_t *undo_page, uint16_t rec, +trx_undo_page_get_next_rec(const buf_block_t *undo_page, const byte *rec, uint32_t page_no, uint16_t offset) { - uint16_t end= trx_undo_page_get_end(undo_page, page_no, offset); - uint16_t next= mach_read_from_2(undo_page->page.frame + rec); + const uint16_t next= mach_read_from_2(rec); + const page_t *upage= undo_page->page.frame; + uint16_t end= trx_undo_page_get_end(undo_page, page_no, upage + offset); ut_ad(next <= end); - return next >= end ? nullptr : undo_page->page.frame + next; + return next >= end ? nullptr : const_cast(upage) + next; } diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 9d268d80f7328..c03ff7059d821 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1120,17 +1120,18 @@ trx_t* lock_sec_rec_some_has_impl( /*=======================*/ trx_t* caller_trx,/*!id == 0 in a locking read if caller_trx has not modified any persistent tables. */ @@ -1620,6 +1621,7 @@ lock_rec_lock( LOCK_GAP or LOCK_REC_NOT_GAP */ const buf_block_t* block, /*!< in: buffer block containing the record */ + const page_t* page, /*!< in: page frame of record */ ulint heap_no,/*!< in: heap number of record */ dict_index_t* index, /*!< in: index of record */ que_thr_t* thr) /*!< in: query thread */ @@ -1672,9 +1674,8 @@ lock_rec_lock( lock->type_mode != mode || lock_rec_get_n_bits(lock) <= heap_no) { - unsigned checked_mode= (heap_no != PAGE_HEAP_NO_SUPREMUM && - lock_mode_is_next_key_lock(mode)) + lock_mode_is_next_key_lock(mode)) ? mode | LOCK_REC_NOT_GAP : mode; @@ -1692,12 +1693,12 @@ lock_rec_lock( have a lock strong enough already granted on the record, we have to wait. */ - err= lock_rec_enqueue_waiting(c_lock, mode, id, block->page.frame, + err= lock_rec_enqueue_waiting(c_lock, mode, id, page, heap_no, index, thr, nullptr); else if (!impl) { /* Set the requested lock on the record. */ - lock_rec_add_to_queue(mode, g.cell(), id, block->page.frame, heap_no, + lock_rec_add_to_queue(mode, g.cell(), id, page, heap_no, index, trx, true); err= DB_SUCCESS_LOCKED_REC; } @@ -1710,7 +1711,7 @@ lock_rec_lock( ut_ad(!impl); lock_reuse_for_next_key_lock(held_lock, mode, g.cell(), id, - block->page.frame, heap_no, index, trx); + page, heap_no, index, trx); } } else if (!impl) @@ -1731,8 +1732,7 @@ lock_rec_lock( /* Simplified and faster path for the most common cases */ if (!impl) - lock_rec_create_low(nullptr, mode, id, block->page.frame, heap_no, index, - trx, false); + lock_rec_create_low(nullptr, mode, id, page, heap_no, index, trx, false); return DB_SUCCESS_LOCKED_REC; } @@ -2458,6 +2458,7 @@ void lock_rec_inherit_to_gap_if_gap_lock( /*================================*/ const buf_block_t* block, /*!< in: buffer block */ + const page_t* page, /*!< in: buffer page */ ulint heir_heap_no, /*!< in: heap_no of record which inherits */ ulint heap_no) /*!< in: heap_no of record @@ -2475,7 +2476,7 @@ lock_rec_inherit_to_gap_if_gap_lock( !lock->is_record_not_gap()) && !lock_table_has(lock->trx, lock->index->table, LOCK_X)) lock_rec_add_to_queue(LOCK_GAP | lock->mode(), - g.cell(), id, block->page.frame, + g.cell(), id, page, heir_heap_no, lock->index, lock->trx, false); } @@ -2487,7 +2488,7 @@ static void lock_rec_move( hash_cell_t& receiver_cell, /*!< in: hash table cell */ - const buf_block_t& receiver, /*!< in: buffer block containing + const page_t* receiver, /*!< in: buffer block containing the receiving record */ const page_id_t receiver_id, /*!< in: page identifier */ const hash_cell_t& donator_cell, /*!< in: hash table cell */ @@ -2521,8 +2522,7 @@ lock_rec_move( the function works also if donator_id == receiver_id */ lock_rec_add_to_queue(type_mode, receiver_cell, - receiver_id, receiver.page.frame, - receiver_heap_no, + receiver_id, receiver, receiver_heap_no, lock->index, lock_trx, true); lock_trx->mutex_unlock(); } @@ -2592,6 +2592,9 @@ lock_move_reorganize_page( return; } + const page_t *page= block->page.frame; + const page_t *opage= oblock->page.frame; + /* We will modify arbitrary trx->lock.trx_locks. Do not bother with a memory transaction; we are going to allocate memory and copy a lot of data. */ @@ -2632,8 +2635,8 @@ lock_move_reorganize_page( } while (lock); - const ulint comp= page_is_comp(block->page.frame); - ut_ad(comp == page_is_comp(oblock->page.frame)); + const ulint comp= page_is_comp(page); + ut_ad(comp == page_is_comp(opage)); lock_move_granted_locks_to_front(old_locks); @@ -2647,8 +2650,8 @@ lock_move_reorganize_page( supremum of the page; the infimum may carry locks if an update of a record is occurring on the page, and its locks were temporarily stored on the infimum */ - const rec_t *rec1= page_get_infimum_rec(block->page.frame); - const rec_t *rec2= page_get_infimum_rec(oblock->page.frame); + const rec_t *rec1= page_get_infimum_rec(page); + const rec_t *rec2= page_get_infimum_rec(opage); /* Set locks according to old locks */ for (;;) @@ -2663,8 +2666,8 @@ lock_move_reorganize_page( old_heap_no= rec_get_heap_no_new(rec2); new_heap_no= rec_get_heap_no_new(rec1); - rec1= page_rec_get_next_low(rec1, TRUE); - rec2= page_rec_get_next_low(rec2, TRUE); + rec1= page_rec_get_next_low(page, rec1, TRUE); + rec2= page_rec_get_next_low(opage, rec2, TRUE); } else { @@ -2672,8 +2675,8 @@ lock_move_reorganize_page( new_heap_no= rec_get_heap_no_old(rec1); ut_ad(!memcmp(rec1, rec2, rec_get_data_size_old(rec2))); - rec1= page_rec_get_next_low(rec1, FALSE); - rec2= page_rec_get_next_low(rec2, FALSE); + rec1= page_rec_get_next_low(page, rec1, FALSE); + rec2= page_rec_get_next_low(opage, rec2, FALSE); } trx_t *lock_trx= lock->trx; @@ -2687,7 +2690,7 @@ lock_move_reorganize_page( /* NOTE that the old lock bitmap could be too small for the new heap number! */ - lock_rec_add_to_queue(lock->type_mode, cell, id, block->page.frame, + lock_rec_add_to_queue(lock->type_mode, cell, id, page, new_heap_no, lock->index, lock_trx, true); } @@ -2729,10 +2732,11 @@ lock_move_rec_list_end( const rec_t* rec) /*!< in: record on page: this is the first record moved */ { - const ulint comp= page_rec_is_comp(rec); - - ut_ad(block->page.frame == page_align(rec)); - ut_ad(comp == page_is_comp(new_block->page.frame)); + const page_t *const page= block->page.frame; + const page_t *const new_page= new_block->page.frame; + const ulint comp= page_is_comp(page); + ut_ad(page == page_align(rec)); + ut_ad(comp == page_is_comp(new_page)); const page_id_t id{block->page.id()}; const page_id_t new_id{new_block->page.id()}; @@ -2754,17 +2758,15 @@ lock_move_rec_list_end( if (comp) { - if (page_offset(rec1) == PAGE_NEW_INFIMUM) - rec1= page_rec_get_next_low(rec1, TRUE); - rec2= page_rec_get_next_low(new_block->page.frame + PAGE_NEW_INFIMUM, - TRUE); + if (rec1 == &page[PAGE_NEW_INFIMUM]) + rec1= page_rec_get_next_low(page, rec1, TRUE); + rec2= page_rec_get_next_low(new_page, new_page + PAGE_NEW_INFIMUM, 1); } else { - if (page_offset(rec1) == PAGE_OLD_INFIMUM) - rec1= page_rec_get_next_low(rec1, FALSE); - rec2= page_rec_get_next_low(new_block->page.frame + PAGE_OLD_INFIMUM, - FALSE); + if (rec1 == &page[PAGE_OLD_INFIMUM]) + rec1= page_rec_get_next_low(page, rec1, FALSE); + rec2= page_rec_get_next_low(new_page, new_page + PAGE_OLD_INFIMUM, 0); } if (UNIV_UNLIKELY(!rec1 || !rec2)) @@ -2786,19 +2788,19 @@ lock_move_rec_list_end( if (comp) { rec1_heap_no= rec_get_heap_no_new(rec1); - if (!(rec1= page_rec_get_next_low(rec1, TRUE))) + if (!(rec1= page_rec_get_next_low(page, rec1, TRUE))) { ut_ad(rec1_heap_no == PAGE_HEAP_NO_SUPREMUM); break; } rec2_heap_no= rec_get_heap_no_new(rec2); - rec2= page_rec_get_next_low(rec2, TRUE); + rec2= page_rec_get_next_low(new_page, rec2, TRUE); } else { ut_d(const rec_t *old1= rec1); rec1_heap_no= rec_get_heap_no_old(rec1); - if (!(rec1= page_rec_get_next_low(rec1, FALSE))) + if (!(rec1= page_rec_get_next_low(page, rec1, FALSE))) { ut_ad(rec1_heap_no == PAGE_HEAP_NO_SUPREMUM); break; @@ -2808,7 +2810,7 @@ lock_move_rec_list_end( ut_ad(!memcmp(old1, rec2, rec_get_data_size_old(old1))); rec2_heap_no= rec_get_heap_no_old(rec2); - rec2= page_rec_get_next_low(rec2, FALSE); + rec2= page_rec_get_next_low(new_page, rec2, FALSE); } if (UNIV_UNLIKELY(!rec2)) @@ -2831,8 +2833,7 @@ lock_move_rec_list_end( lock->type_mode&= ~LOCK_WAIT; } - lock_rec_add_to_queue(type_mode, g.cell2(), new_id, - new_block->page.frame, + lock_rec_add_to_queue(type_mode, g.cell2(), new_id, new_page, rec2_heap_no, lock->index, lock_trx, true); } @@ -2871,11 +2872,13 @@ lock_move_rec_list_start( before the records were copied */ { - const ulint comp= page_rec_is_comp(rec); + const page_t *page= block->page.frame; + const ulint comp= page_is_comp(page); + const page_t *new_page= new_block->page.frame; - ut_ad(block->page.frame == page_align(rec)); - ut_ad(comp == page_is_comp(new_block->page.frame)); - ut_ad(new_block->page.frame == page_align(old_end)); + ut_ad(page_align(rec) == page); + ut_ad(comp == page_is_comp(new_page)); + ut_ad(page_align(old_end) == new_page); ut_ad(!page_rec_is_metadata(rec)); const page_id_t id{block->page.id()}; const page_id_t new_id{new_block->page.id()}; @@ -2893,15 +2896,13 @@ lock_move_rec_list_start( if (comp) { - rec1= page_rec_get_next_low(block->page.frame + PAGE_NEW_INFIMUM, - TRUE); - rec2= page_rec_get_next_low(old_end, TRUE); + rec1= page_rec_get_next_low(page, page + PAGE_NEW_INFIMUM, TRUE); + rec2= page_rec_get_next_low(new_page, old_end, TRUE); } else { - rec1= page_rec_get_next_low(block->page.frame + PAGE_OLD_INFIMUM, - FALSE); - rec2= page_rec_get_next_low(old_end, FALSE); + rec1= page_rec_get_next_low(page, page + PAGE_OLD_INFIMUM, FALSE); + rec2= page_rec_get_next_low(new_page, old_end, FALSE); } /* Copy lock requests on user records to new page and @@ -2926,8 +2927,8 @@ lock_move_rec_list_start( rec1_heap_no= rec_get_heap_no_new(rec1); rec2_heap_no= rec_get_heap_no_new(rec2); - rec1= page_rec_get_next_low(rec1, TRUE); - rec2= page_rec_get_next_low(rec2, TRUE); + rec1= page_rec_get_next_low(page, rec1, TRUE); + rec2= page_rec_get_next_low(new_page, rec2, TRUE); } else { @@ -2936,8 +2937,8 @@ lock_move_rec_list_start( ut_ad(!memcmp(rec1, rec2, rec_get_data_size_old(rec2))); - rec1= page_rec_get_next_low(rec1, FALSE); - rec2= page_rec_get_next_low(rec2, FALSE); + rec1= page_rec_get_next_low(page, rec1, FALSE); + rec2= page_rec_get_next_low(new_page, rec2, FALSE); } trx_t *lock_trx= lock->trx; @@ -2954,8 +2955,7 @@ lock_move_rec_list_start( lock->type_mode&= ~LOCK_WAIT; } - lock_rec_add_to_queue(type_mode, g.cell2(), new_id, - new_block->page.frame, + lock_rec_add_to_queue(type_mode, g.cell2(), new_id, new_page, rec2_heap_no, lock->index, lock_trx, true); } @@ -2963,7 +2963,7 @@ lock_move_rec_list_start( } #ifdef UNIV_DEBUG - if (page_rec_is_supremum(rec)) + if (page_rec_is_supremum(page, rec)) for (auto i= lock_rec_get_n_bits(lock); --i > PAGE_HEAP_NO_USER_LOW; ) ut_ad(!lock_rec_get_nth_bit(lock, i)); #endif /* UNIV_DEBUG */ @@ -2992,11 +2992,12 @@ lock_rtr_move_rec_list( if (!num_move) return; - const ulint comp= page_rec_is_comp(rec_move[0].old_rec); + const page_t *const new_page= page_align(rec_move[0].new_rec); + const ulint comp= page_rec_is_comp(new_page); ut_ad(block->page.frame == page_align(rec_move[0].old_rec)); - ut_ad(new_block->page.frame == page_align(rec_move[0].new_rec)); - ut_ad(comp == page_rec_is_comp(rec_move[0].new_rec)); + ut_ad(new_block->page.frame == new_page); + ut_ad(comp == page_rec_is_comp(rec_move[0].old_rec)); const page_id_t id{block->page.id()}; const page_id_t new_id{new_block->page.id()}; @@ -3049,8 +3050,7 @@ lock_rtr_move_rec_list( lock->type_mode&= ~LOCK_WAIT; } - lock_rec_add_to_queue(type_mode, g.cell2(), new_id, - new_block->page.frame, + lock_rec_add_to_queue(type_mode, g.cell2(), new_id, new_page, rec2_heap_no, lock->index, lock_trx, true); rec_move[moved].moved= true; @@ -3073,7 +3073,9 @@ lock_update_split_right( const buf_block_t* right_block, /*!< in: right page */ const buf_block_t* left_block) /*!< in: left page */ { - const ulint h= lock_get_min_heap_no(right_block); + const page_t *right_page= right_block->page.frame; + const page_t *left_page= left_block->page.frame; + const ulint h= lock_get_min_heap_no(right_page); const page_id_t l{left_block->page.id()}; const page_id_t r{right_block->page.id()}; @@ -3083,25 +3085,25 @@ lock_update_split_right( /* Move the locks on the supremum of the left page to the supremum of the right page */ - lock_rec_move(g.cell2(), *right_block, r, g.cell1(), l, + lock_rec_move(g.cell2(), right_page, r, g.cell1(), l, PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM); /* Inherit the locks to the supremum of left page from the successor of the infimum on right page */ lock_rec_inherit_to_gap(g.cell1(), l, g.cell2(), r, - left_block->page.frame, PAGE_HEAP_NO_SUPREMUM, - h); + left_page, PAGE_HEAP_NO_SUPREMUM, h); } void lock_update_node_pointer(const buf_block_t *left_block, const buf_block_t *right_block) { - const ulint h= lock_get_min_heap_no(right_block); + const page_t *right_page= right_block->page.frame; + const ulint h= lock_get_min_heap_no(right_page); const page_id_t l{left_block->page.id()}; const page_id_t r{right_block->page.id()}; LockMultiGuard g{lock_sys.rec_hash, l, r}; - lock_rec_inherit_to_gap(g.cell2(), r, g.cell1(), l, right_block->page.frame, + lock_rec_inherit_to_gap(g.cell2(), r, g.cell1(), l, right_page, h, PAGE_HEAP_NO_SUPREMUM); } @@ -3141,6 +3143,7 @@ lock_update_merge_right( { ut_ad(!page_rec_is_metadata(orig_succ)); + const page_t *right_page= right_block->page.frame; const page_id_t l{left_block->page.id()}; const page_id_t r{right_block->page.id()}; /* This would likely be too large for a memory transaction. */ @@ -3149,8 +3152,8 @@ lock_update_merge_right( /* Inherit the locks from the supremum of the left page to the original successor of infimum on the right page, to which the left page was merged */ - lock_rec_inherit_to_gap(g.cell2(), r, g.cell1(), l, right_block->page.frame, - page_rec_get_heap_no(orig_succ), + lock_rec_inherit_to_gap(g.cell2(), r, g.cell1(), l, right_page, + page_rec_get_heap_no(right_page, orig_succ), PAGE_HEAP_NO_SUPREMUM); /* Reset the locks on the supremum of the left page, releasing @@ -3169,11 +3172,12 @@ of the root page will act as a dummy carrier of the locks of the record to be updated. */ void lock_update_root_raise(const buf_block_t &block, const page_id_t root) { + const page_t *const page= block.page.frame; const page_id_t id{block.page.id()}; /* This would likely be too large for a memory transaction. */ LockMultiGuard g{lock_sys.rec_hash, id, root}; /* Move the locks on the supremum of the root to the supremum of block */ - lock_rec_move(g.cell1(), block, id, g.cell2(), root, + lock_rec_move(g.cell1(), page, id, g.cell2(), root, PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM); } @@ -3182,11 +3186,12 @@ void lock_update_root_raise(const buf_block_t &block, const page_id_t root) @param old old page (not index root page) */ void lock_update_copy_and_discard(const buf_block_t &new_block, page_id_t old) { + const page_t *const page= new_block.page.frame; const page_id_t id{new_block.page.id()}; /* This would likely be too large for a memory transaction. */ LockMultiGuard g{lock_sys.rec_hash, id, old}; /* Move the locks on the supremum of the old page to the supremum of new */ - lock_rec_move(g.cell1(), new_block, id, g.cell2(), old, + lock_rec_move(g.cell1(), page, id, g.cell2(), old, PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM); lock_rec_free_all_from_discard_page(old, g.cell2(), lock_sys.rec_hash); } @@ -3199,15 +3204,16 @@ lock_update_split_left( const buf_block_t* right_block, /*!< in: right page */ const buf_block_t* left_block) /*!< in: left page */ { - ulint h= lock_get_min_heap_no(right_block); + ulint h= lock_get_min_heap_no(right_block->page.frame); + const page_t *left_page= left_block->page.frame; + const page_id_t l{left_block->page.id()}; const page_id_t r{right_block->page.id()}; LockMultiGuard g{lock_sys.rec_hash, l, r}; /* Inherit the locks to the supremum of the left page from the successor of the infimum on the right page */ lock_rec_inherit_to_gap(g.cell1(), l, g.cell2(), r, - left_block->page.frame, PAGE_HEAP_NO_SUPREMUM, - h); + left_page, PAGE_HEAP_NO_SUPREMUM, h); } /** Update the lock table when a page is merged to the left. @@ -3217,10 +3223,10 @@ lock_update_split_left( void lock_update_merge_left(const buf_block_t& left, const rec_t *orig_pred, const page_id_t right) { - ut_ad(left.page.frame == page_align(orig_pred)); - const page_id_t l{left.page.id()}; - const rec_t *left_next_rec= page_rec_get_next_const(orig_pred); + const page_t *const left_page= left.page.frame; + const rec_t *left_next_rec= page_rec_get_next(left_page, orig_pred); + if (UNIV_UNLIKELY(!left_next_rec)) { ut_ad("corrupted page" == 0); @@ -3229,12 +3235,12 @@ void lock_update_merge_left(const buf_block_t& left, const rec_t *orig_pred, /* This would likely be too large for a memory transaction. */ LockMultiGuard g{lock_sys.rec_hash, l, right}; - if (!page_rec_is_supremum(left_next_rec)) + if (!page_rec_is_supremum(left_page, left_next_rec)) { /* Inherit the locks on the supremum of the left page to the first record which was moved from the right page */ - lock_rec_inherit_to_gap(g.cell1(), l, g.cell1(), l, left.page.frame, - page_rec_get_heap_no(left_next_rec), + lock_rec_inherit_to_gap(g.cell1(), l, g.cell1(), l, left_page, + page_rec_get_heap_no(left_page, left_next_rec), PAGE_HEAP_NO_SUPREMUM); /* Reset the locks on the supremum of the left page, @@ -3244,7 +3250,7 @@ void lock_update_merge_left(const buf_block_t& left, const rec_t *orig_pred, /* Move the locks from the supremum of right page to the supremum of the left page */ - lock_rec_move(g.cell1(), left, l, g.cell2(), right, + lock_rec_move(g.cell1(), left_page, l, g.cell2(), right, PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM); lock_rec_free_all_from_discard_page(right, g.cell2(), lock_sys.rec_hash); @@ -3270,12 +3276,13 @@ lock_rec_reset_and_inherit_gap_locks( ulint heap_no) /*!< in: heap_no of the donating record */ { + const page_t *heir_page= heir_block.page.frame; const page_id_t heir{heir_block.page.id()}; /* This is a rare operation and likely too large for a memory transaction. */ LockMultiGuard g{lock_sys.rec_hash, heir, donor}; lock_rec_reset_and_release_wait(g.cell1(), heir, heir_heap_no); lock_rec_inherit_to_gap(g.cell1(), heir, g.cell2(), donor, - heir_block.page.frame, heir_heap_no, heap_no); + heir_page, heir_heap_no, heap_no); } /*************************************************************//** @@ -3290,6 +3297,7 @@ lock_update_discard( const buf_block_t* block) /*!< in: index page which will be discarded */ { + const page_t* heir_page = heir_block->page.frame; const page_t* page = block->page.frame; const rec_t* rec; ulint heap_no; @@ -3311,7 +3319,7 @@ lock_update_discard( lock_rec_inherit_to_gap(g.cell1(), heir, g.cell2(), page_id, - heir_block->page.frame, + heir_page, heir_heap_no, heap_no); lock_rec_reset_and_release_wait( @@ -3327,7 +3335,7 @@ lock_update_discard( lock_rec_inherit_to_gap(g.cell1(), heir, g.cell2(), page_id, - heir_block->page.frame, + heir_page, heir_heap_no, heap_no); lock_rec_reset_and_release_wait( @@ -3367,22 +3375,24 @@ lock_update_insert( ulint receiver_heap_no; ulint donator_heap_no; - ut_ad(block->page.frame == page_align(rec)); + const page_t* const page = block->page.frame; + + ut_ad(page == page_align(rec)); ut_ad(!page_rec_is_metadata(rec)); /* Inherit the gap-locking locks for rec, in gap mode, from the next record */ - if (page_rec_is_comp(rec)) { + if (page_is_comp(page)) { receiver_heap_no = rec_get_heap_no_new(rec); - rec = page_rec_get_next_low(rec, TRUE); + rec = page_rec_get_next_low(page, rec, TRUE); if (UNIV_UNLIKELY(!rec)) { return; } donator_heap_no = rec_get_heap_no_new(rec); } else { receiver_heap_no = rec_get_heap_no_old(rec); - rec = page_rec_get_next_low(rec, FALSE); + rec = page_rec_get_next_low(page, rec, FALSE); if (UNIV_UNLIKELY(!rec)) { return; } @@ -3390,7 +3400,7 @@ lock_update_insert( } lock_rec_inherit_to_gap_if_gap_lock( - block, receiver_heap_no, donator_heap_no); + block, page, receiver_heap_no, donator_heap_no); } /*************************************************************//** @@ -3425,7 +3435,7 @@ lock_update_delete( /* Let the next record inherit the locks from rec, in gap mode */ - lock_rec_inherit_to_gap(g.cell(), id, g.cell(), id, block->page.frame, + lock_rec_inherit_to_gap(g.cell(), id, g.cell(), id, page, next_heap_no, heap_no); /* Reset the lock bits on rec and release waiting transactions */ @@ -3449,16 +3459,16 @@ lock_rec_store_on_page_infimum( bits are reset on the record */ { - const ulint heap_no= page_rec_get_heap_no(rec); - - ut_ad(block->page.frame == page_align(rec)); + const page_t *const page= block->page.frame; + const ulint heap_no= page_rec_get_heap_no(page, rec); const page_id_t id{block->page.id()}; + ut_ad(block->page.frame == page); #ifdef ENABLED_DEBUG_SYNC SCOPE_EXIT([]() { DEBUG_SYNC_C("lock_rec_store_on_page_infimum_end"); }); #endif LockGuard g{lock_sys.rec_hash, id}; - lock_rec_move(g.cell(), *block, id, g.cell(), id, + lock_rec_move(g.cell(), page, id, g.cell(), id, PAGE_HEAP_NO_INFIMUM, heap_no); } @@ -3471,10 +3481,11 @@ whose infimum stored the lock state; lock bits are reset on the infimum */ void lock_rec_restore_from_page_infimum(const buf_block_t &block, const rec_t *rec, page_id_t donator) { - const ulint heap_no= page_rec_get_heap_no(rec); + const page_t *const page= block.page.frame; + const ulint heap_no= page_rec_get_heap_no(page, rec); const page_id_t id{block.page.id()}; LockMultiGuard g{lock_sys.rec_hash, id, donator}; - lock_rec_move(g.cell1(), block, id, g.cell2(), donator, heap_no, + lock_rec_move(g.cell1(), page, id, g.cell2(), donator, heap_no, PAGE_HEAP_NO_INFIMUM); } @@ -4165,7 +4176,7 @@ lock_rec_unlock( ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); ut_ad(!page_rec_is_metadata(rec)); - heap_no = page_rec_get_heap_no(rec); + heap_no = page_rec_get_heap_no(page_align(rec), rec); LockGuard g{lock_sys.rec_hash, id}; @@ -4443,7 +4454,9 @@ static void lock_rec_unlock_unmodified(hash_cell_t &cell, lock_t *lock, btr_block_get(*index, lock->un_member.rec_lock.page_id.page_no(), RW_S_LATCH, true, &mtr)) { - if (UNIV_UNLIKELY(!page_is_leaf(block->page.frame))) + const page_t *const page= block->page.frame; + + if (UNIV_UNLIKELY(!page_is_leaf(page))) { ut_ad("corrupted lock system" == 0); goto func_exit; @@ -4452,8 +4465,7 @@ static void lock_rec_unlock_unmodified(hash_cell_t &cell, lock_t *lock, for (ulint i= PAGE_HEAP_NO_USER_LOW; i < lock_rec_get_n_bits(lock); ++i) { if (!lock_rec_get_nth_bit(lock, i)); - else if (const rec_t *rec= - page_find_rec_with_heap_no(block->page.frame, i)) + else if (const rec_t *rec= page_find_rec_with_heap_no(page, i)) { if (index->is_clust()) { @@ -4468,7 +4480,7 @@ static void lock_rec_unlock_unmodified(hash_cell_t &cell, lock_t *lock, offsets= rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); if (lock->trx != - lock_sec_rec_some_has_impl(lock->trx, rec, index, offsets)) + lock_sec_rec_some_has_impl(lock->trx, page, rec, index, offsets)) goto unlock_rec; } } @@ -4814,6 +4826,7 @@ static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr) mtr.start(); const buf_block_t* block = buf_page_try_get(page_id, &mtr); + const page_t* page = block ? block->page.frame : nullptr; for (ulint i = 0; i < lock_rec_get_n_bits(lock); ++i) { @@ -4823,12 +4836,11 @@ static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr) fprintf(file, "Record lock, heap no %lu", (ulong) i); - if (block) { - ut_ad(page_is_leaf(block->page.frame)); + if (page) { + ut_ad(page_is_leaf(page)); const rec_t* rec; - rec = page_find_rec_with_heap_no( - buf_block_get_frame(block), i); + rec = page_find_rec_with_heap_no(page, i); ut_ad(!page_rec_is_metadata(rec)); offsets = rec_get_offsets( @@ -5142,14 +5154,14 @@ lock_rec_queue_validate( const lock_t* lock; ulint heap_no; - ut_a(rec); + const page_t* const page = page_align(rec); ut_ad(rec_offs_validate(rec, index, offsets)); - ut_ad(!page_rec_is_comp(rec) == !rec_offs_comp(offsets)); - ut_ad(page_rec_is_leaf(rec)); - ut_ad(!index || dict_index_is_clust(index) + ut_ad(!page_is_comp(page) == !rec_offs_comp(offsets)); + ut_ad(page_is_leaf(page)); + ut_ad(!index || index->is_primary() || !dict_index_is_online_ddl(index)); - heap_no = page_rec_get_heap_no(rec); + heap_no = page_rec_get_heap_no(page, rec); if (!locked_lock_trx_sys) { lock_sys.wr_lock(SRW_LOCK_CALL); @@ -5158,7 +5170,7 @@ lock_rec_queue_validate( hash_cell_t &cell= *lock_sys.rec_hash.cell_get(id.fold()); lock_sys.assert_locked(cell); - if (!page_rec_is_user_rec(rec)) { + if (!page_rec_is_user_rec(page, rec)) { for (lock = lock_sys_t::get_first(cell, id, heap_no); lock != NULL; @@ -5310,6 +5322,7 @@ static bool lock_rec_validate_page(const buf_block_t *block, bool latched) rec_offs* offsets = offsets_; rec_offs_init(offsets_); + const page_t* page = block->page.frame; const page_id_t id{block->page.id()}; LockGuard g{lock_sys.rec_hash, id}; @@ -5341,7 +5354,7 @@ static bool lock_rec_validate_page(const buf_block_t *block, bool latched) bool locked = lock_rec_get_nth_bit(lock, i); if (locked || i == PAGE_HEAP_NO_SUPREMUM) { - rec = page_find_rec_with_heap_no(block->page.frame, i); + rec = page_find_rec_with_heap_no(page, i); ut_a(rec); ut_ad(!locked || page_rec_is_leaf(rec)); @@ -5514,19 +5527,20 @@ lock_rec_insert_check_and_lock( LOCK_GAP type locks from the successor record */ { - ut_ad(block->page.frame == page_align(rec)); + const page_t *const page= block->page.frame; + ut_ad(page == page_align(rec)); ut_ad(mtr->is_named_space(index->table->space)); - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_is_leaf(page)); ut_ad(!index->table->is_temporary()); - const rec_t *next_rec= page_rec_get_next_const(rec); + const rec_t *next_rec= page_rec_get_next(page, rec); if (UNIV_UNLIKELY(!next_rec || rec_is_metadata(next_rec, *index))) return DB_CORRUPTION; dberr_t err= DB_SUCCESS; bool inherit_in= *inherit; trx_t *trx= thr_get_trx(thr); - ulint heap_no= page_rec_get_heap_no(next_rec); + ulint heap_no= page_rec_get_heap_no(page, next_rec); const page_id_t id{block->page.id()}; { @@ -5565,7 +5579,7 @@ lock_rec_insert_check_and_lock( heap_no, trx)) { trx->mutex_lock(); - err= lock_rec_enqueue_waiting(c_lock, type_mode, id, block->page.frame, + err= lock_rec_enqueue_waiting(c_lock, type_mode, id, page, heap_no, index, thr, nullptr); trx->mutex_unlock(); } @@ -5615,16 +5629,19 @@ has an implicit lock on the record. @return trx, with the reference released */ static trx_t *lock_rec_convert_impl_to_expl_for_trx(trx_t *trx, const page_id_t id, + const page_t *page, const rec_t *rec, dict_index_t *index) { + ut_ad(page == page_align(rec)); + if (trx) { ut_ad(trx->is_referenced()); - ut_ad(page_rec_is_leaf(rec)); + ut_ad(page_is_leaf(page)); ut_ad(!rec_is_metadata(rec, *index)); - ulint heap_no= page_rec_get_heap_no(rec); + ulint heap_no= page_rec_get_heap_no(page, rec); { LockGuard g{lock_sys.rec_hash, id}; @@ -5635,7 +5652,7 @@ static trx_t *lock_rec_convert_impl_to_expl_for_trx(trx_t *trx, !lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, g.cell(), id, heap_no, trx)) lock_rec_add_to_queue(LOCK_X | LOCK_REC_NOT_GAP, g.cell(), id, - page_align(rec), heap_no, index, trx, true); + page, heap_no, index, trx, true); } trx->release_reference(); @@ -5691,11 +5708,12 @@ static my_bool lock_rec_other_trx_holds_expl_callback(void *el, void *a) @param caller_trx trx of current thread @param[in] trx trx holding implicit lock on rec - @param[in] rec user record + @param[in] page index leaf page + @param[in] rec user record on page @param[in] id page identifier */ static void lock_rec_other_trx_holds_expl(trx_t *caller_trx, trx_t *trx, - const rec_t *rec, + const page_t *page, const rec_t *rec, const page_id_t id) { if (trx) @@ -5709,7 +5727,7 @@ static void lock_rec_other_trx_holds_expl(trx_t *caller_trx, trx_t *trx, /* The transaction was committed before we acquired LockGuard. */ return; lock_rec_other_trx_holds_expl_arg arg= - { page_rec_get_heap_no(rec), g.cell(), id, *trx }; + { page_rec_get_heap_no(page, rec), g.cell(), id, *trx }; trx_sys.rw_trx_hash.iterate(caller_trx, lock_rec_other_trx_holds_expl_callback, &arg); } @@ -5729,7 +5747,7 @@ should be created. @tparam is_primary whether the index is the primary key @param[in,out] caller_trx current transaction -@param[in] id index tree leaf page identifier +@param[in] block index tree leaf page @param[in] rec record on the leaf page @param[in] index the index of the record @param[in] offsets rec_get_offsets(rec,index) @@ -5740,18 +5758,20 @@ static const trx_t * lock_rec_convert_impl_to_expl( trx_t* caller_trx, - page_id_t id, + const buf_block_t& block, const rec_t* rec, dict_index_t* index, const rec_offs* offsets) { - trx_t* trx; + trx_t* trx; + const page_t* const page = block.page.frame; + const page_id_t id{block.page.id()}; lock_sys.assert_unlocked(); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); ut_ad(rec_offs_validate(rec, index, offsets)); - ut_ad(!page_rec_is_comp(rec) == !rec_offs_comp(offsets)); - ut_ad(page_rec_is_leaf(rec)); + ut_ad(!page_is_comp(page) == !rec_offs_comp(offsets)); + ut_ad(page_is_leaf(page)); ut_ad(!rec_is_metadata(rec, *index)); ut_ad(index->is_primary() == is_primary); @@ -5771,17 +5791,18 @@ lock_rec_convert_impl_to_expl( } else { ut_ad(!dict_index_is_online_ddl(index)); - trx = lock_sec_rec_some_has_impl(caller_trx, rec, index, + trx = lock_sec_rec_some_has_impl(caller_trx, page, rec, index, offsets); if (trx == caller_trx) { trx->release_reference(); return trx; } - ut_d(lock_rec_other_trx_holds_expl(caller_trx, trx, rec, id)); + ut_d(lock_rec_other_trx_holds_expl(caller_trx, trx, + page, rec, id)); } - return lock_rec_convert_impl_to_expl_for_trx(trx, id, rec, index); + return lock_rec_convert_impl_to_expl_for_trx(trx, id, page, rec, index); } /*********************************************************************//** @@ -5804,11 +5825,12 @@ lock_clust_rec_modify_check_and_lock( { dberr_t err; ulint heap_no; + const page_t* const page = block->page.frame; ut_ad(rec_offs_validate(rec, index, offsets)); - ut_ad(page_rec_is_leaf(rec)); - ut_ad(dict_index_is_clust(index)); - ut_ad(block->page.frame == page_align(rec)); + ut_ad(page_is_leaf(page)); + ut_ad(index->is_primary()); + ut_ad(page == page_align(rec)); ut_ad(!rec_is_metadata(rec, *index)); ut_ad(!index->table->is_temporary()); @@ -5822,7 +5844,7 @@ lock_clust_rec_modify_check_and_lock( trx_t *trx = thr_get_trx(thr); if (const trx_t *owner = - lock_rec_convert_impl_to_expl(trx, block->page.id(), + lock_rec_convert_impl_to_expl(trx, *block, rec, index, offsets)) { if (owner == trx) { /* We already hold an exclusive lock. */ @@ -5835,7 +5857,7 @@ lock_clust_rec_modify_check_and_lock( } err = lock_rec_lock(true, LOCK_X | LOCK_REC_NOT_GAP, - block, heap_no, index, thr); + block, page, heap_no, index, thr); ut_ad(lock_rec_queue_validate(false, block->page.id(), rec, index, offsets)); @@ -5867,14 +5889,13 @@ lock_sec_rec_modify_check_and_lock( (can be NULL if BTR_NO_LOCKING_FLAG) */ mtr_t* mtr) /*!< in/out: mini-transaction */ { - dberr_t err; - ulint heap_no; + const page_t* const page = block->page.frame; ut_ad(!dict_index_is_clust(index)); ut_ad(!dict_index_is_online_ddl(index) || (flags & BTR_CREATE_FLAG)); - ut_ad(block->page.frame == page_align(rec)); + ut_ad(page == page_align(rec)); ut_ad(mtr->is_named_space(index->table->space)); - ut_ad(page_rec_is_leaf(rec)); + ut_ad(page_is_leaf(page)); ut_ad(!rec_is_metadata(rec, *index)); if (flags & BTR_NO_LOCKING_FLAG) { @@ -5883,7 +5904,7 @@ lock_sec_rec_modify_check_and_lock( } ut_ad(!index->table->is_temporary()); - heap_no = page_rec_get_heap_no(rec); + ulint heap_no = page_rec_get_heap_no(page, rec); #ifdef WITH_WSREP trx_t *trx= thr_get_trx(thr); @@ -5903,8 +5924,8 @@ lock_sec_rec_modify_check_and_lock( index record, and this would not have been possible if another active transaction had modified this secondary index record. */ - err = lock_rec_lock(true, LOCK_X | LOCK_REC_NOT_GAP, - block, heap_no, index, thr); + dberr_t err = lock_rec_lock(true, LOCK_X | LOCK_REC_NOT_GAP, + block, page, heap_no, index, thr); #ifdef WITH_WSREP if (trx->wsrep == 3) trx->wsrep = 1; @@ -5974,9 +5995,9 @@ lock_sec_rec_read_check_and_lock( ut_ad(!dict_index_is_clust(index)); ut_ad(!dict_index_is_online_ddl(index)); ut_ad(block->page.frame == page_align(rec)); - ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec)); + ut_ad(!page_rec_is_infimum(block->page.frame, rec)); ut_ad(rec_offs_validate(rec, index, offsets)); - ut_ad(page_rec_is_leaf(rec)); + ut_ad(page_is_leaf(block->page.frame)); ut_ad(mode == LOCK_X || mode == LOCK_S); if ((flags & BTR_NO_LOCKING_FLAG) @@ -5994,9 +6015,11 @@ lock_sec_rec_read_check_and_lock( return DB_SUCCESS; } - if (page_rec_is_supremum(rec)) { + const page_t* const page = block->page.frame; + + if (page_rec_is_supremum(page, rec)) { } else if (const trx_t *owner = - lock_rec_convert_impl_to_expl(trx, block->page.id(), + lock_rec_convert_impl_to_expl(trx, *block, rec, index, offsets)) { if (owner == trx) { if (gap_mode == LOCK_REC_NOT_GAP) { @@ -6022,7 +6045,8 @@ lock_sec_rec_read_check_and_lock( #endif /* WITH_WSREP */ err = lock_rec_lock(false, gap_mode | mode, - block, page_rec_get_heap_no(rec), index, thr); + block, page, page_rec_get_heap_no(page, rec), + index, thr); #ifdef WITH_WSREP if (trx->wsrep == 3) trx->wsrep = 1; @@ -6065,13 +6089,14 @@ lock_clust_rec_read_check_and_lock( LOCK_REC_NOT_GAP */ que_thr_t* thr) /*!< in: query thread */ { - ut_ad(dict_index_is_clust(index)); - ut_ad(block->page.frame == page_align(rec)); - ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec)); + const page_t* page = block->page.frame; + + ut_ad(index->is_primary()); + ut_ad(page_rec_is_user_rec(page, rec) || page_rec_is_supremum(page, rec)); ut_ad(gap_mode == LOCK_ORDINARY || gap_mode == LOCK_GAP || gap_mode == LOCK_REC_NOT_GAP); ut_ad(rec_offs_validate(rec, index, offsets)); - ut_ad(page_rec_is_leaf(rec)); + ut_ad(page_is_leaf(page)); ut_ad(!rec_is_metadata(rec, *index)); if ((flags & BTR_NO_LOCKING_FLAG) @@ -6081,15 +6106,13 @@ lock_clust_rec_read_check_and_lock( return(DB_SUCCESS); } - const page_id_t id{block->page.id()}; - - ulint heap_no = page_rec_get_heap_no(rec); + ulint heap_no = page_rec_get_heap_no(page, rec); trx_t *trx = thr_get_trx(thr); if (lock_table_has(trx, index->table, LOCK_X) || heap_no == PAGE_HEAP_NO_SUPREMUM) { } else if (const trx_t *owner = - lock_rec_convert_impl_to_expl(trx, id, + lock_rec_convert_impl_to_expl(trx, *block, rec, index, offsets)) { if (owner == trx) { if (gap_mode == LOCK_REC_NOT_GAP) { @@ -6111,9 +6134,10 @@ lock_clust_rec_read_check_and_lock( } dberr_t err = lock_rec_lock(false, gap_mode | mode, - block, heap_no, index, thr); + block, page, heap_no, index, thr); - ut_ad(lock_rec_queue_validate(false, id, rec, index, offsets)); + ut_ad(lock_rec_queue_validate(false, block->page.id(), + rec, index, offsets)); DEBUG_SYNC_C("after_lock_clust_rec_read_check_and_lock"); @@ -6997,13 +7021,15 @@ void lock_update_split_and_merge( supremum on the left page before merge*/ const buf_block_t* right_block) /*!< in: right page from which merged */ { - ut_ad(page_is_leaf(left_block->page.frame)); - ut_ad(page_is_leaf(right_block->page.frame)); - ut_ad(page_align(orig_pred) == left_block->page.frame); + const page_t *left_page= left_block->page.frame; + const page_t *right_page= right_block->page.frame; + + ut_ad(page_is_leaf(left_page)); + ut_ad(page_is_leaf(right_page)); const page_id_t l{left_block->page.id()}; const page_id_t r{right_block->page.id()}; - const rec_t *left_next_rec= page_rec_get_next_const(orig_pred); + const rec_t *left_next_rec= page_rec_get_next(left_page, orig_pred); if (UNIV_UNLIKELY(!left_next_rec)) { ut_ad("corrupted page" == 0); @@ -7016,8 +7042,8 @@ void lock_update_split_and_merge( /* Inherit the locks on the supremum of the left page to the first record which was moved from the right page */ - lock_rec_inherit_to_gap(g.cell1(), l, g.cell1(), l, left_block->page.frame, - page_rec_get_heap_no(left_next_rec), + lock_rec_inherit_to_gap(g.cell1(), l, g.cell1(), l, left_page, + page_rec_get_heap_no(left_page, left_next_rec), PAGE_HEAP_NO_SUPREMUM); /* Reset the locks on the supremum of the left page, @@ -7026,7 +7052,7 @@ void lock_update_split_and_merge( /* Inherit the locks to the supremum of the left page from the successor of the infimum on the right page */ - lock_rec_inherit_to_gap(g.cell1(), l, g.cell2(), r, left_block->page.frame, + lock_rec_inherit_to_gap(g.cell1(), l, g.cell2(), r, left_page, PAGE_HEAP_NO_SUPREMUM, - lock_get_min_heap_no(right_block)); + lock_get_min_heap_no(right_page)); } diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index ed69302302517..9ffc6fef4be02 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -158,8 +158,9 @@ struct log_phys_t : public log_rec_t size_t len) { ut_ad(len > 2); + page_t *page= block.page.frame; byte *free_p= my_assume_aligned<2> - (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + block.page.frame); + (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + page); const uint16_t free= mach_read_from_2(free_p); if (UNIV_UNLIKELY(free < TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE || free + len + 6 >= srv_page_size - FIL_PAGE_DATA_END)) @@ -169,7 +170,7 @@ struct log_phys_t : public log_rec_t return true; } - byte *p= block.page.frame + free; + byte *p= page + free; mach_write_to_2(free_p, free + 4 + len); memcpy(p, free_p, 2); p+= 2; @@ -337,9 +338,9 @@ struct log_phys_t : public log_rec_t page_create_low(&block, *l != INIT_ROW_FORMAT_REDUNDANT); break; case UNDO_INIT: - if (UNIV_UNLIKELY(rlen != 1)) + if (UNIV_UNLIKELY(rlen != 1 || block.page.zip.data)) goto record_corrupted; - trx_undo_page_init(block); + trx_undo_page_init(block, frame); break; case UNDO_APPEND: if (UNIV_UNLIKELY(rlen <= 3)) @@ -2302,9 +2303,9 @@ bool recv_sys_t::add(map::iterator it, lsn_t start_lsn, lsn_t lsn, ut_calc_align(static_cast(size), ALIGNMENT); static_assert(ut_is_2pow(ALIGNMENT), "ALIGNMENT must be a power of 2"); UT_LIST_ADD_FIRST(blocks, block); - MEM_MAKE_ADDRESSABLE(block->page.frame, size); - MEM_NOACCESS(block->page.frame + size, srv_page_size - size); buf= block->page.frame; + MEM_MAKE_ADDRESSABLE(buf, size); + MEM_NOACCESS(static_cast(buf) + size, srv_page_size - size); } else { @@ -2323,8 +2324,8 @@ bool recv_sys_t::add(map::iterator it, lsn_t start_lsn, lsn_t lsn, block->page.access_time= ((block->page.access_time >> 16) + 1) << 16 | ut_calc_align(static_cast(free_offset), ALIGNMENT); - MEM_MAKE_ADDRESSABLE(block->page.frame + free_offset - size, size); buf= block->page.frame + free_offset - size; + MEM_MAKE_ADDRESSABLE(buf, size); } recs.log.append(new (my_assume_aligned(buf)) @@ -3129,14 +3130,13 @@ static buf_block_t *recv_recover_page(buf_block_t *block, mtr_t &mtr, if (start_lsn) { ut_ad(end_lsn >= start_lsn); mach_write_to_8(FIL_PAGE_LSN + frame, end_lsn); - if (UNIV_LIKELY(frame == block->page.frame)) { + if (UNIV_LIKELY_NULL(block->page.zip.data)) { + buf_zip_decompress(block, false); + } else { mach_write_to_8(srv_page_size - FIL_PAGE_END_LSN_OLD_CHKSUM + frame, end_lsn); - } else { - buf_zip_decompress(block, false); } - buf_block_modify_clock_inc(block); mysql_mutex_lock(&log_sys.flush_order_mutex); buf_flush_note_modification(block, start_lsn, end_lsn); @@ -3272,7 +3272,6 @@ void IORequest::fake_read_complete(os_offset_t offset) const mtr.start(); mtr.set_log_mode(MTR_LOG_NO_REDO); - ut_ad(bpage->frame); /* Move the ownership of the x-latch on the page to this OS thread, so that we can acquire a second x-latch on it. This is needed for the operations to the page to pass the debug checks. */ diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index d6306f7b1c1fb..52bca95445882 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -971,9 +971,10 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch) #endif done: + ut_d(const page_t *page= block->page.frame); ut_ad(state < buf_page_t::UNFIXED || - page_id_t(page_get_space_id(block->page.frame), - page_get_page_no(block->page.frame)) == block->page.id()); + page_id_t(page_get_space_id(page), + page_get_page_no(page)) == block->page.id()); memo_push(block, fix_type); } @@ -1010,8 +1011,9 @@ void mtr_t::upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch) #ifdef BTR_CUR_HASH_ADAPT btr_search_drop_page_hash_index(block, true); #endif - ut_ad(page_id_t(page_get_space_id(block->page.frame), - page_get_page_no(block->page.frame)) == block->page.id()); + ut_d(const page_t *page= block->page.frame); + ut_ad(page_id_t(page_get_space_id(page), + page_get_page_no(page)) == block->page.id()); } #ifdef UNIV_DEBUG diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index f83b4d774b19e..a72e8b247ea8f 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -42,6 +42,7 @@ static ulint page_cur_short_succ; /** Try a search shortcut based on the last insert. @param[in] block index page +@param[in] page index page frame @param[in] index index tree @param[in] tuple search key @param[in,out] iup_matched_fields already matched fields in the @@ -54,6 +55,7 @@ UNIV_INLINE bool page_cur_try_search_shortcut( const buf_block_t* block, + const page_t* page, const dict_index_t* index, const dtuple_t* tuple, ulint* iup_matched_fields, @@ -65,7 +67,6 @@ page_cur_try_search_shortcut( ulint low_match; ulint up_match; ibool success = FALSE; - const page_t* page = buf_block_get_frame(block); mem_heap_t* heap = NULL; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; @@ -79,7 +80,7 @@ page_cur_try_search_shortcut( dtuple_get_n_fields(tuple), &heap); ut_ad(rec); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); low_match = up_match = std::min(*ilow_matched_fields, *iup_matched_fields); @@ -88,11 +89,11 @@ page_cur_try_search_shortcut( goto exit_func; } - if (!(next_rec = page_rec_get_next_const(rec))) { + if (!(next_rec = page_rec_get_next(page, rec))) { goto exit_func; } - if (!page_rec_is_supremum(next_rec)) { + if (!page_rec_is_supremum(page, next_rec)) { offsets = rec_get_offsets(next_rec, index, offsets, index->n_core_fields, dtuple_get_n_fields(tuple), &heap); @@ -122,6 +123,7 @@ page_cur_try_search_shortcut( /** Try a search shortcut based on the last insert. @param[in] block index page +@param[in] page index page frame @param[in] index index tree @param[in] tuple search key @param[in,out] iup_matched_fields already matched fields in the @@ -138,6 +140,7 @@ UNIV_INLINE bool page_cur_try_search_shortcut_bytes( const buf_block_t* block, + const page_t* page, const dict_index_t* index, const dtuple_t* tuple, ulint* iup_matched_fields, @@ -153,7 +156,6 @@ page_cur_try_search_shortcut_bytes( ulint up_match; ulint up_bytes; ibool success = FALSE; - const page_t* page = buf_block_get_frame(block); mem_heap_t* heap = NULL; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; @@ -167,7 +169,7 @@ page_cur_try_search_shortcut_bytes( dtuple_get_n_fields(tuple), &heap); ut_ad(rec); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); if (ut_pair_cmp(*ilow_matched_fields, *ilow_matched_bytes, *iup_matched_fields, *iup_matched_bytes) < 0) { up_match = low_match = *ilow_matched_fields; @@ -182,11 +184,11 @@ page_cur_try_search_shortcut_bytes( goto exit_func; } - if (!(next_rec = page_rec_get_next_const(rec))) { + if (!(next_rec = page_rec_get_next(page, rec))) { goto exit_func; } - if (!page_rec_is_supremum(next_rec)) { + if (!page_rec_is_supremum(page, next_rec)) { offsets = rec_get_offsets(next_rec, index, offsets, index->n_core_fields, dtuple_get_n_fields(tuple), &heap); @@ -292,7 +294,6 @@ page_cur_search_with_match( ulint up; ulint low; ulint mid; - const page_t* page; const rec_t* up_rec; const rec_t* low_rec; const rec_t* mid_rec; @@ -302,6 +303,7 @@ page_cur_search_with_match( int cmp; const dict_index_t* const index = cursor->index; const buf_block_t* const block = cursor->block; + const page_t* const page = block->page.frame; #ifdef UNIV_ZIP_DEBUG const page_zip_des_t* page_zip = buf_block_get_page_zip(block); #endif /* UNIV_ZIP_DEBUG */ @@ -322,7 +324,6 @@ page_cur_search_with_match( || mode == PAGE_CUR_G || mode == PAGE_CUR_GE || dict_index_is_spatial(index)); #endif /* UNIV_DEBUG */ - page = buf_block_get_frame(block); #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ @@ -338,7 +339,7 @@ page_cur_search_with_match( && !index->is_spatial() && page_header_get_field(page, PAGE_N_DIRECTION) > 3 && page_cur_try_search_shortcut( - block, index, tuple, + block, page, index, tuple, iup_matched_fields, ilow_matched_fields, cursor)) { return false; } @@ -391,8 +392,8 @@ page_cur_search_with_match( while (up - low > 1) { mid = (low + up) / 2; const page_dir_slot_t* slot = page_dir_get_nth_slot(page, mid); - if (UNIV_UNLIKELY(!(mid_rec - = page_dir_slot_get_rec_validate(slot)))) { + mid_rec = page_dir_slot_get_rec_validate(page, slot); + if (UNIV_UNLIKELY(!mid_rec)) { goto corrupted; } cur_matched_fields = std::min(low_matched_fields, @@ -438,9 +439,9 @@ page_cur_search_with_match( } low_rec = page_dir_slot_get_rec_validate( - page_dir_get_nth_slot(page, low)); + page, page_dir_get_nth_slot(page, low)); up_rec = page_dir_slot_get_rec_validate( - page_dir_get_nth_slot(page, up)); + page, page_dir_get_nth_slot(page, up)); if (UNIV_UNLIKELY(!low_rec || !up_rec)) { corrupted: if (UNIV_LIKELY_NULL(heap)) { @@ -453,7 +454,7 @@ page_cur_search_with_match( distance 1 of each other. */ for (;;) { - if (const rec_t* next = page_rec_get_next_const(low_rec)) { + if (const rec_t* next = page_rec_get_next(page, low_rec)) { if (next == up_rec) { break; } @@ -497,16 +498,12 @@ page_cur_search_with_match( ) { if (!cmp && !cur_matched_fields) { #ifdef UNIV_DEBUG - mtr_t mtr; - mtr_start(&mtr); - /* We got a match, but cur_matched_fields is 0, it must have REC_INFO_MIN_REC_FLAG */ ulint rec_info = rec_get_info_bits(mid_rec, rec_offs_comp(offsets)); ut_ad(rec_info & REC_INFO_MIN_REC_FLAG); ut_ad(!page_has_prev(page)); - mtr_commit(&mtr); #endif cur_matched_fields = dtuple_get_n_fields_cmp(tuple); @@ -594,7 +591,7 @@ page_cur_search_with_match_bytes( ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE || mode == PAGE_CUR_G || mode == PAGE_CUR_GE); #endif /* UNIV_DEBUG */ - page = buf_block_get_frame(block); + page = block->page.frame; #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ @@ -608,7 +605,7 @@ page_cur_search_with_match_bytes( && mode == PAGE_CUR_LE && page_header_get_field(page, PAGE_N_DIRECTION) > 3 && page_cur_try_search_shortcut_bytes( - block, index, tuple, + block, page, index, tuple, iup_matched_fields, iup_matched_bytes, ilow_matched_fields, ilow_matched_bytes, cursor)) { @@ -652,7 +649,7 @@ page_cur_search_with_match_bytes( while (up - low > 1) { const ulint mid = (low + up) / 2; mid_rec = page_dir_slot_get_rec_validate( - page_dir_get_nth_slot(page, mid)); + page, page_dir_get_nth_slot(page, mid)); if (UNIV_UNLIKELY(!mid_rec)) { goto corrupted; } @@ -703,9 +700,9 @@ page_cur_search_with_match_bytes( } low_rec = page_dir_slot_get_rec_validate( - page_dir_get_nth_slot(page, low)); + page, page_dir_get_nth_slot(page, low)); up_rec = page_dir_slot_get_rec_validate( - page_dir_get_nth_slot(page, up)); + page, page_dir_get_nth_slot(page, up)); if (UNIV_UNLIKELY(!low_rec || !up_rec)) { corrupted: if (UNIV_LIKELY_NULL(heap)) { @@ -718,7 +715,7 @@ page_cur_search_with_match_bytes( distance 1 of each other. */ for (;;) { - if (const rec_t* next = page_rec_get_next_const(low_rec)) { + if (const rec_t* next = page_rec_get_next(page, low_rec)) { if (next == up_rec) { break; } @@ -798,21 +795,9 @@ page_cur_search_with_match_bytes( } #endif /* BTR_CUR_HASH_ADAPT */ -/***********************************************************//** -Positions a page cursor on a randomly chosen user record on a page. If there -are no user records, sets the cursor on the infimum record. */ -void page_cur_open_on_rnd_user_rec(page_cur_t *cursor) -{ - if (const ulint n_recs= page_get_n_recs(cursor->block->page.frame)) - if ((cursor->rec= page_rec_get_nth(cursor->block->page.frame, - ut_rnd_interval(n_recs) + 1))) - return; - cursor->rec= page_get_infimum_rec(cursor->block->page.frame); -} - /** Set the number of owned records. -@param[in,out] rec record in block.frame +@param[in,out] rec record in buffer page frame @param[in] n_owned number of records skipped in the sparse page directory @param[in] comp whether ROW_FORMAT is COMPACT or DYNAMIC */ static void page_rec_set_n_owned(rec_t *rec, ulint n_owned, bool comp) @@ -834,18 +819,20 @@ static bool page_dir_split_slot(const buf_block_t &block, const ulint n_owned= PAGE_DIR_SLOT_MAX_N_OWNED + 1; - ut_ad(page_dir_slot_get_n_owned(slot) == n_owned); static_assert((PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED, "compatibility"); + page_t *const page= block.page.frame; + ut_ad(page_dir_slot_get_n_owned(page, slot) == n_owned); /* Find a record approximately in the middle. */ - const rec_t *rec= page_dir_slot_get_rec_validate(slot + PAGE_DIR_SLOT_SIZE); + const rec_t *rec= + page_dir_slot_get_rec_validate(page, slot + PAGE_DIR_SLOT_SIZE); for (ulint i= n_owned / 2; i--; ) { if (UNIV_UNLIKELY(!rec)) return true; - rec= page_rec_get_next_const(rec); + rec= page_rec_get_next(page, rec); } if (UNIV_UNLIKELY(!rec)) @@ -853,11 +840,11 @@ static bool page_dir_split_slot(const buf_block_t &block, /* Add a directory slot immediately below this one. */ constexpr uint16_t n_slots_f= PAGE_N_DIR_SLOTS + PAGE_HEADER; - byte *n_slots_p= my_assume_aligned<2>(n_slots_f + block.page.frame); + byte *n_slots_p= my_assume_aligned<2>(n_slots_f + page); const uint16_t n_slots= mach_read_from_2(n_slots_p); page_dir_slot_t *last_slot= static_cast - (block.page.frame + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) - + (page + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) - n_slots * PAGE_DIR_SLOT_SIZE); if (UNIV_UNLIKELY(slot < last_slot)) @@ -870,10 +857,10 @@ static bool page_dir_split_slot(const buf_block_t &block, mach_write_to_2(n_slots_p, n_slots + 1); - mach_write_to_2(slot, rec - block.page.frame); - const bool comp= page_is_comp(block.page.frame) != 0; - page_rec_set_n_owned(page_dir_slot_get_rec(slot), half_owned, comp); - page_rec_set_n_owned(page_dir_slot_get_rec(slot - PAGE_DIR_SLOT_SIZE), + mach_write_to_2(slot, rec - page); + const bool comp= page_is_comp(page) != 0; + page_rec_set_n_owned(page_dir_slot_get_rec(page, slot), half_owned, comp); + page_rec_set_n_owned(page_dir_slot_get_rec(page, slot - PAGE_DIR_SLOT_SIZE), n_owned - half_owned, comp); return false; } @@ -881,40 +868,42 @@ static bool page_dir_split_slot(const buf_block_t &block, /** Split a directory slot which owns too many records. @param[in,out] block index page (ROW_FORMAT=COMPRESSED) +@param[in,out] page uncompressed index page frame @param[in] s the slot that needs to be split @param[in,out] mtr mini-transaction */ -static void page_zip_dir_split_slot(buf_block_t *block, ulint s, mtr_t* mtr) +static void page_zip_dir_split_slot(buf_block_t *block, page_t *page, + ulint s, mtr_t* mtr) { ut_ad(block->page.zip.data); - ut_ad(page_is_comp(block->page.frame)); + ut_ad(page_is_comp(page)); ut_ad(s); - page_dir_slot_t *slot= page_dir_get_nth_slot(block->page.frame, s); + page_dir_slot_t *slot= page_dir_get_nth_slot(page, s); const ulint n_owned= PAGE_DIR_SLOT_MAX_N_OWNED + 1; - ut_ad(page_dir_slot_get_n_owned(slot) == n_owned); + ut_ad(page_dir_slot_get_n_owned(page, slot) == n_owned); static_assert((PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED, "compatibility"); /* 1. We loop to find a record approximately in the middle of the records owned by the slot. */ - const rec_t *rec= page_dir_slot_get_rec(slot + PAGE_DIR_SLOT_SIZE); + const rec_t *rec= page_dir_slot_get_rec(page, slot + PAGE_DIR_SLOT_SIZE); /* We do not try to prevent crash on corruption here. For ROW_FORMAT=COMPRESSED pages, the next-record links should be validated in page_zip_decompress(). Corruption should only be possible here if the buffer pool was corrupted later. */ for (ulint i= n_owned / 2; i--; ) - rec= page_rec_get_next_const(rec); + rec= page_rec_get_next(page, rec); /* Add a directory slot immediately below this one. */ constexpr uint16_t n_slots_f= PAGE_N_DIR_SLOTS + PAGE_HEADER; - byte *n_slots_p= my_assume_aligned<2>(n_slots_f + block->page.frame); + byte *n_slots_p= my_assume_aligned<2>(n_slots_f + page); const uint16_t n_slots= mach_read_from_2(n_slots_p); page_dir_slot_t *last_slot= static_cast - (block->page.frame + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) - + (page + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) - n_slots * PAGE_DIR_SLOT_SIZE); memmove_aligned<2>(last_slot, last_slot + PAGE_DIR_SLOT_SIZE, slot - last_slot); @@ -925,11 +914,12 @@ static void page_zip_dir_split_slot(buf_block_t *block, ulint s, mtr_t* mtr) /* Log changes to the compressed page header and the dense page directory. */ memcpy_aligned<2>(&block->page.zip.data[n_slots_f], n_slots_p, 2); - mach_write_to_2(slot, page_offset(rec)); - page_rec_set_n_owned(block, page_dir_slot_get_rec(slot), half_owned, - true, mtr); + mach_write_to_2(slot, rec - page); + page_rec_set_n_owned(block, page_dir_slot_get_rec(page, slot), + half_owned, true, mtr); page_rec_set_n_owned(block, - page_dir_slot_get_rec(slot - PAGE_DIR_SLOT_SIZE), + page_dir_slot_get_rec(page, + slot - PAGE_DIR_SLOT_SIZE), n_owned - half_owned, true, mtr); } @@ -938,15 +928,18 @@ Try to balance an underfilled directory slot with an adjacent one, so that there are at least the minimum number of records owned by the slot; this may result in merging the two slots. @param[in,out] block ROW_FORMAT=COMPRESSED page +@param[in,out] page uncompressed page frame @param[in] s the slot to be balanced @param[in,out] mtr mini-transaction */ -static void page_zip_dir_balance_slot(buf_block_t *block, ulint s, mtr_t *mtr) +static void page_zip_dir_balance_slot(buf_block_t *block, page_t *page, + ulint s, mtr_t *mtr) { ut_ad(block->page.zip.data); - ut_ad(page_is_comp(block->page.frame)); + ut_ad(page_is_comp(page)); + ut_ad(page == block->page.frame); ut_ad(s > 0); - const ulint n_slots = page_dir_get_n_slots(block->page.frame); + const ulint n_slots = page_dir_get_n_slots(page); if (UNIV_UNLIKELY(s + 1 == n_slots)) { /* The last directory slot cannot be balanced. */ @@ -955,14 +948,14 @@ static void page_zip_dir_balance_slot(buf_block_t *block, ulint s, mtr_t *mtr) ut_ad(s < n_slots); - page_dir_slot_t* slot = page_dir_get_nth_slot(block->page.frame, s); + page_dir_slot_t* slot = page_dir_get_nth_slot(page, s); rec_t* const up_rec = const_cast - (page_dir_slot_get_rec(slot - PAGE_DIR_SLOT_SIZE)); + (page_dir_slot_get_rec(page, slot - PAGE_DIR_SLOT_SIZE)); rec_t* const slot_rec = const_cast - (page_dir_slot_get_rec(slot)); + (page_dir_slot_get_rec(page, slot)); const ulint up_n_owned = rec_get_n_owned_new(up_rec); - ut_ad(rec_get_n_owned_new(page_dir_slot_get_rec(slot)) + ut_ad(rec_get_n_owned_new(page_dir_slot_get_rec(page, slot)) == PAGE_DIR_SLOT_MIN_N_OWNED - 1); if (up_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) { @@ -975,12 +968,11 @@ static void page_zip_dir_balance_slot(buf_block_t *block, ulint s, mtr_t *mtr) true, mtr); /* Shift the slots */ page_dir_slot_t* last_slot = page_dir_get_nth_slot( - block->page.frame, n_slots - 1); + page, n_slots - 1); memmove_aligned<2>(last_slot + PAGE_DIR_SLOT_SIZE, last_slot, slot - last_slot); constexpr uint16_t n_slots_f = PAGE_N_DIR_SLOTS + PAGE_HEADER; - byte *n_slots_p= my_assume_aligned<2> - (n_slots_f + block->page.frame); + byte *n_slots_p= my_assume_aligned<2>(n_slots_f + page); mtr->write<2>(*block, n_slots_p, n_slots - 1); memcpy_aligned<2>(n_slots_f + block->page.zip.data, n_slots_p, 2); @@ -990,7 +982,7 @@ static void page_zip_dir_balance_slot(buf_block_t *block, ulint s, mtr_t *mtr) /* Transfer one record to the underfilled slot */ page_rec_set_n_owned(block, slot_rec, 0, true, mtr); - const rec_t* new_rec = page_rec_get_next_low(slot_rec, TRUE); + const rec_t* new_rec = page_rec_get_next_low(page, slot_rec, TRUE); /* We do not try to prevent crash on corruption here. For ROW_FORMAT=COMPRESSED pages, the next-record links should be validated in page_zip_decompress(). Corruption should only @@ -998,7 +990,7 @@ static void page_zip_dir_balance_slot(buf_block_t *block, ulint s, mtr_t *mtr) page_rec_set_n_owned(block, const_cast(new_rec), PAGE_DIR_SLOT_MIN_N_OWNED, true, mtr); - mach_write_to_2(slot, page_offset(new_rec)); + mach_write_to_2(slot, new_rec - page); page_rec_set_n_owned(up_rec, up_n_owned - 1, true); } @@ -1007,14 +999,17 @@ Try to balance an underfilled directory slot with an adjacent one, so that there are at least the minimum number of records owned by the slot; this may result in merging the two slots. @param[in,out] block index page +@param[in,out] page index page frame @param[in] s the slot to be balanced */ -static void page_dir_balance_slot(const buf_block_t &block, ulint s) +static void page_dir_balance_slot(const buf_block_t &block, page_t *page, + ulint s) { - const bool comp= page_is_comp(block.page.frame); + const bool comp= page_is_comp(page); + ut_ad(page == block.page.frame); ut_ad(!block.page.zip.data); ut_ad(s > 0); - const ulint n_slots = page_dir_get_n_slots(block.page.frame); + const ulint n_slots = page_dir_get_n_slots(page); if (UNIV_UNLIKELY(s + 1 == n_slots)) { /* The last directory slot cannot be balanced. */ @@ -1023,16 +1018,16 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s) ut_ad(s < n_slots); - page_dir_slot_t* slot = page_dir_get_nth_slot(block.page.frame, s); + page_dir_slot_t* slot = page_dir_get_nth_slot(page, s); rec_t* const up_rec = const_cast - (page_dir_slot_get_rec(slot - PAGE_DIR_SLOT_SIZE)); + (page_dir_slot_get_rec(page, slot - PAGE_DIR_SLOT_SIZE)); rec_t* const slot_rec = const_cast - (page_dir_slot_get_rec(slot)); + (page_dir_slot_get_rec(page, slot)); const ulint up_n_owned = comp ? rec_get_n_owned_new(up_rec) : rec_get_n_owned_old(up_rec); - ut_ad(page_dir_slot_get_n_owned(slot) + ut_ad(page_dir_slot_get_n_owned(page, slot) == PAGE_DIR_SLOT_MIN_N_OWNED - 1); if (up_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) { @@ -1044,13 +1039,12 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s) + (PAGE_DIR_SLOT_MIN_N_OWNED - 1), comp); /* Shift the slots */ page_dir_slot_t* last_slot = page_dir_get_nth_slot( - block.page.frame, n_slots - 1); + page, n_slots - 1); memmove_aligned<2>(last_slot + PAGE_DIR_SLOT_SIZE, last_slot, slot - last_slot); memset_aligned<2>(last_slot, 0, 2); constexpr uint16_t n_slots_f = PAGE_N_DIR_SLOTS + PAGE_HEADER; - byte *n_slots_p= my_assume_aligned<2> - (n_slots_f + block.page.frame); + byte *n_slots_p= my_assume_aligned<2>(n_slots_f + page); mach_write_to_2(n_slots_p, n_slots - 1); return; } @@ -1059,8 +1053,8 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s) const rec_t* new_rec; if (comp) { - if (UNIV_UNLIKELY(!(new_rec = - page_rec_get_next_low(slot_rec, true)))) { + new_rec = page_rec_get_next_low(page, slot_rec, true); + if (UNIV_UNLIKELY(!new_rec)) { ut_ad("corrupted page" == 0); return; } @@ -1069,8 +1063,8 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s) PAGE_DIR_SLOT_MIN_N_OWNED, true); page_rec_set_n_owned(up_rec, up_n_owned - 1, true); } else { - if (UNIV_UNLIKELY(!(new_rec = - page_rec_get_next_low(slot_rec, false)))) { + new_rec = page_rec_get_next_low(page, slot_rec, false); + if (UNIV_UNLIKELY(!new_rec)) { ut_ad("corrupted page" == 0); return; } @@ -1080,32 +1074,31 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s) page_rec_set_n_owned(up_rec, up_n_owned - 1, false); } - mach_write_to_2(slot, page_offset(new_rec)); + mach_write_to_2(slot, new_rec - page); } /** Allocate space for inserting an index record. @tparam compressed whether to update the ROW_FORMAT=COMPRESSED @param[in,out] block index page +@param[in,out] page index page frame @param[in] need number of bytes needed @param[out] heap_no record heap number @return pointer to the start of the allocated buffer @retval NULL if allocation fails */ template -static byte* page_mem_alloc_heap(buf_block_t *block, ulint need, +static byte* page_mem_alloc_heap(buf_block_t *block, page_t *page, ulint need, ulint *heap_no) { ut_ad(!compressed || block->page.zip.data); - byte *heap_top= my_assume_aligned<2>(PAGE_HEAP_TOP + PAGE_HEADER + - block->page.frame); + byte *heap_top= my_assume_aligned<2>(PAGE_HEAP_TOP + PAGE_HEADER + page); const uint16_t top= mach_read_from_2(heap_top); - if (need > page_get_max_insert_size(block->page.frame, 1)) + if (need > page_get_max_insert_size(page, 1)) return NULL; - byte *n_heap= my_assume_aligned<2> - (PAGE_N_HEAP + PAGE_HEADER + block->page.frame); + byte *n_heap= my_assume_aligned<2>(PAGE_N_HEAP + PAGE_HEADER + page); const uint16_t h= mach_read_from_2(n_heap); if (UNIV_UNLIKELY((h + 1) & 0x6000)) @@ -1131,7 +1124,7 @@ static byte* page_mem_alloc_heap(buf_block_t *block, ulint need, heap_top, 4); } - return &block->page.frame[top]; + return &page[top]; } /** Write log for inserting a B-tree or R-tree record in @@ -1156,14 +1149,14 @@ inline void mtr_t::page_insert(const buf_block_t &block, bool reuse, { ut_ad(!block.page.zip.data); ut_ad(m_log_mode == MTR_LOG_ALL); - ut_d(ulint n_slots= page_dir_get_n_slots(block.page.frame)); + ut_d(const page_t *const page= block.page.frame); + ut_d(ulint n_slots= page_dir_get_n_slots(page)); ut_ad(n_slots >= 2); ut_d(const byte *page_end= - page_dir_get_nth_slot(block.page.frame, n_slots - 1)); - ut_ad(&block.page.frame[prev_rec + PAGE_OLD_INFIMUM] <= page_end); - ut_ad(block.page.frame + - page_header_get_offs(block.page.frame, PAGE_HEAP_TOP) <= page_end); - ut_ad(fil_page_index_page_check(block.page.frame)); + page_dir_get_nth_slot(page, n_slots - 1)); + ut_ad(&page[prev_rec + PAGE_OLD_INFIMUM] <= page_end); + ut_ad(page + page_header_get_offs(page, PAGE_HEAP_TOP) <= page_end); + ut_ad(fil_page_index_page_check(page)); ut_ad(!(~(REC_INFO_MIN_REC_FLAG | REC_INFO_DELETED_FLAG) & info_bits)); ut_ad(n_fields_s >= 2); ut_ad((n_fields_s >> 1) <= REC_MAX_N_FIELDS); @@ -1242,16 +1235,15 @@ inline void mtr_t::page_insert(const buf_block_t &block, bool reuse, { ut_ad(!block.page.zip.data); ut_ad(m_log_mode == MTR_LOG_ALL); - ut_d(ulint n_slots= page_dir_get_n_slots(block.page.frame)); + ut_d(const page_t *const page= block.page.frame); + ut_d(ulint n_slots= page_dir_get_n_slots(page)); ut_ad(n_slots >= 2); - ut_d(const byte *page_end= page_dir_get_nth_slot(block.page.frame, - n_slots - 1)); - ut_ad(&block.page.frame[prev_rec + PAGE_NEW_INFIMUM] <= page_end); - ut_ad(block.page.frame + - page_header_get_offs(block.page.frame, PAGE_HEAP_TOP) <= page_end); - ut_ad(fil_page_index_page_check(block.page.frame)); + ut_d(const byte *page_end= page_dir_get_nth_slot(page, n_slots - 1)); + ut_ad(&page[prev_rec + PAGE_NEW_INFIMUM] <= page_end); + ut_ad(page + page_header_get_offs(page, PAGE_HEAP_TOP) <= page_end); + ut_ad(fil_page_index_page_check(page)); ut_ad(hdr_l + hdr_c + data_l + data_c <= static_cast - (page_end - &block.page.frame[PAGE_NEW_SUPREMUM_END])); + (page_end - &page[PAGE_NEW_SUPREMUM_END])); ut_ad(reuse || shift == 0); #ifdef UNIV_DEBUG switch (~(REC_INFO_MIN_REC_FLAG | REC_INFO_DELETED_FLAG) & info_status) { @@ -1259,11 +1251,11 @@ inline void mtr_t::page_insert(const buf_block_t &block, bool reuse, ut_ad(0); break; case REC_STATUS_NODE_PTR: - ut_ad(!page_is_leaf(block.page.frame)); + ut_ad(!page_is_leaf(page)); break; case REC_STATUS_INSTANT: case REC_STATUS_ORDINARY: - ut_ad(page_is_leaf(block.page.frame)); + ut_ad(page_is_leaf(page)); } #endif @@ -1347,6 +1339,47 @@ static void page_cur_directory_corrupted(const buf_block_t &block, << " is corrupted"; } +/** Looks for the directory slot which owns the given record. +@param page index page +@param rec index record +@return the directory slot number +@retval ULINT_UNDEFINED on corruption */ +ulint page_dir_find_owner_slot(const page_t *page, const rec_t *rec) +{ + ut_ad(page == page_align(rec)); + ut_ad(page_rec_check(page, rec)); + + const page_dir_slot_t *first_slot= page_dir_get_nth_slot(page, 0); + const page_dir_slot_t *slot= + page_dir_get_nth_slot(page, ulint(page_dir_get_n_slots(page)) - 1); + const rec_t *r = rec; + + if (page_is_comp(page)) + while (rec_get_n_owned_new(r) == 0) + { + r= page_rec_get_next_low(page, r, true); + if (UNIV_UNLIKELY(r < page + PAGE_NEW_SUPREMUM || r >= slot)) + return ULINT_UNDEFINED; + } + else + while (rec_get_n_owned_old(r) == 0) + { + r= page_rec_get_next_low(page, r, false); + if (UNIV_UNLIKELY(r < page + PAGE_OLD_SUPREMUM || r >= slot)) + return ULINT_UNDEFINED; + } + + while (UNIV_LIKELY(*(uint16*) slot != mach_encode_2(ulint(r - page)))) + { + if (UNIV_UNLIKELY(slot == first_slot)) + return ULINT_UNDEFINED; + + slot+= PAGE_DIR_SLOT_SIZE; + } + + return ulint(first_slot - slot) / PAGE_DIR_SLOT_SIZE; +} + /***********************************************************//** Inserts a record next to page cursor on an uncompressed page. @return pointer to record @@ -1361,18 +1394,18 @@ page_cur_insert_rec_low( { buf_block_t *block= cur->block; dict_index_t * const index= cur->index; + page_t *const page= page_cur_get_page(cur); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_n_fields(offsets) > 0); - ut_ad(index->table->not_redundant() == !!page_is_comp(block->page.frame)); - ut_ad(!!page_is_comp(block->page.frame) == !!rec_offs_comp(offsets)); - ut_ad(fil_page_index_page_check(block->page.frame)); - ut_ad(mach_read_from_8(PAGE_HEADER + PAGE_INDEX_ID + block->page.frame) == - index->id || + ut_ad(index->table->not_redundant() == !!page_is_comp(page)); + ut_ad(!!page_is_comp(page) == !!rec_offs_comp(offsets)); + ut_ad(fil_page_index_page_check(page)); + ut_ad(mach_read_from_8(PAGE_HEADER + PAGE_INDEX_ID + page) == index->id || mtr->is_inside_ibuf()); - ut_ad(page_dir_get_n_slots(block->page.frame) >= 2); + ut_ad(page_dir_get_n_slots(page) >= 2); - ut_ad(!page_rec_is_supremum(cur->rec)); + ut_ad(!page_rec_is_supremum(page, cur->rec)); /* We should not write log for ROW_FORMAT=COMPRESSED pages here. */ ut_ad(!mtr->is_logged() || @@ -1387,7 +1420,7 @@ page_cur_insert_rec_low( rec - rec_offs_extra_size(offsets); ulint extra_size __attribute__((unused))= rec_offs_extra_size(offsets) - - (page_is_comp(block->page.frame) + (page_rec_is_comp(cur->rec) ? REC_N_NEW_EXTRA_BYTES : REC_N_OLD_EXTRA_BYTES); /* All data bytes of the record must be valid. */ @@ -1403,10 +1436,10 @@ page_cur_insert_rec_low( ulint heap_no; byte *insert_buf; - const bool comp= page_is_comp(block->page.frame); + const bool comp= page_is_comp(page); const ulint extra_size= rec_offs_extra_size(offsets); - if (rec_t* free_rec= page_header_get_ptr(block->page.frame, PAGE_FREE)) + if (rec_t* free_rec= page_header_get_ptr(page, PAGE_FREE)) { /* Try to reuse the head of PAGE_FREE. */ rec_offs foffsets_[REC_OFFS_NORMAL_SIZE]; @@ -1415,7 +1448,7 @@ page_cur_insert_rec_low( rec_offs_init(foffsets_); rec_offs *foffsets= rec_get_offsets(free_rec, index, foffsets_, - page_is_leaf(block->page.frame) + page_is_leaf(page) ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); const ulint fextra_size= rec_offs_extra_size(foffsets); @@ -1428,15 +1461,13 @@ page_cur_insert_rec_low( if (too_small) goto use_heap; - byte *page_free= my_assume_aligned<2>(PAGE_FREE + PAGE_HEADER + - block->page.frame); + byte *page_free= my_assume_aligned<2>(PAGE_FREE + PAGE_HEADER + page); if (comp) { heap_no= rec_get_heap_no_new(free_rec); uint16_t next= mach_read_from_2(free_rec - REC_NEXT); mach_write_to_2(page_free, next - ? static_cast(free_rec + next - - block->page.frame) + ? static_cast(free_rec + next - page) : 0); } else @@ -1456,7 +1487,7 @@ page_cur_insert_rec_low( else { use_heap: - insert_buf= page_mem_alloc_heap(block, rec_size, &heap_no); + insert_buf= page_mem_alloc_heap(block, page, rec_size, &heap_no); if (UNIV_UNLIKELY(!insert_buf)) return nullptr; @@ -1464,40 +1495,39 @@ page_cur_insert_rec_low( ut_ad(cur->rec != insert_buf + extra_size); - rec_t *next_rec= block->page.frame + rec_get_next_offs(cur->rec, comp); - ut_ad(next_rec != block->page.frame); + rec_t *next_rec= page + rec_get_next_offs(cur->rec, comp); + ut_ad(next_rec != page); /* Update page header fields */ byte *page_last_insert= my_assume_aligned<2>(PAGE_LAST_INSERT + PAGE_HEADER + - block->page.frame); + page); const uint16_t last_insert= mach_read_from_2(page_last_insert); ut_ad(!last_insert || !comp || - rec_get_node_ptr_flag(block->page.frame + last_insert) == + rec_get_node_ptr_flag(page + last_insert) == rec_get_node_ptr_flag(rec)); /* Write PAGE_LAST_INSERT */ - mach_write_to_2(page_last_insert, page_offset(insert_buf + extra_size)); + mach_write_to_2(page_last_insert, insert_buf + extra_size - page); /* Update PAGE_DIRECTION_B, PAGE_N_DIRECTION if needed */ - if (block->page.frame[FIL_PAGE_TYPE + 1] != byte(FIL_PAGE_RTREE)) + if (page[FIL_PAGE_TYPE + 1] != byte(FIL_PAGE_RTREE)) { - byte *dir= &block->page.frame[PAGE_DIRECTION_B + PAGE_HEADER]; - byte *n= my_assume_aligned<2> - (&block->page.frame[PAGE_N_DIRECTION + PAGE_HEADER]); + byte *dir= &page[PAGE_DIRECTION_B + PAGE_HEADER]; + byte *n= my_assume_aligned<2>(&page[PAGE_N_DIRECTION + PAGE_HEADER]); if (UNIV_UNLIKELY(!last_insert)) { no_direction: *dir= static_cast((*dir & ~((1U << 3) - 1)) | PAGE_NO_DIRECTION); memset(n, 0, 2); } - else if (block->page.frame + last_insert == cur->rec && + else if (page + last_insert == cur->rec && (*dir & ((1U << 3) - 1)) != PAGE_LEFT) { *dir= static_cast((*dir & ~((1U << 3) - 1)) | PAGE_RIGHT); inc_dir: mach_write_to_2(n, mach_read_from_2(n) + 1); } - else if (next_rec == block->page.frame + last_insert && + else if (next_rec == page + last_insert && (*dir & ((1U << 3) - 1)) != PAGE_RIGHT) { *dir= static_cast((*dir & ~((1U << 3) - 1)) | PAGE_LEFT); @@ -1508,8 +1538,7 @@ page_cur_insert_rec_low( } /* Update PAGE_N_RECS. */ - byte *page_n_recs= my_assume_aligned<2>(PAGE_N_RECS + PAGE_HEADER + - block->page.frame); + byte *page_n_recs= my_assume_aligned<2>(PAGE_N_RECS + PAGE_HEADER + page); mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1); @@ -1539,17 +1568,17 @@ page_cur_insert_rec_low( } switch (rec_get_status(rec)) { case REC_STATUS_NODE_PTR: - ut_ad(!page_is_leaf(block->page.frame)); + ut_ad(!page_is_leaf(page)); break; case REC_STATUS_INSTANT: ut_ad(index->is_instant()); - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_is_leaf(page)); if (!rec_is_metadata(rec, true)) break; - ut_ad(cur->rec == &block->page.frame[PAGE_NEW_INFIMUM]); + ut_ad(cur->rec == &page[PAGE_NEW_INFIMUM]); break; case REC_STATUS_ORDINARY: - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_is_leaf(page)); ut_ad(!(rec_get_info_bits(rec, true) & ~REC_INFO_DELETED_FLAG)); break; case REC_STATUS_INFIMUM: @@ -1570,8 +1599,8 @@ page_cur_insert_rec_low( static_cast(insert_rec - cur->rec)); while (!(n_owned= rec_get_n_owned_new(next_rec))) { - next_rec= block->page.frame + rec_get_next_offs(next_rec, true); - ut_ad(next_rec != block->page.frame); + next_rec= page + rec_get_next_offs(next_rec, true); + ut_ad(next_rec != page); } rec_set_bit_field_1(next_rec, n_owned + 1, REC_NEW_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); @@ -1583,8 +1612,7 @@ page_cur_insert_rec_low( const byte * const c_start= cur->rec - extra_size; if (extra_size > REC_N_NEW_EXTRA_BYTES && - c_start >= - &block->page.frame[PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES]) + c_start >= &page[PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES]) { /* Find common header bytes with the preceding record. */ const byte *r= rec - (REC_N_NEW_EXTRA_BYTES + 1); @@ -1597,11 +1625,11 @@ page_cur_insert_rec_low( else { #ifdef UNIV_DEBUG - if (!page_is_leaf(block->page.frame)); + if (!page_is_leaf(page)); else if (rec_is_metadata(rec, false)) { ut_ad(index->is_instant()); - ut_ad(cur->rec == &block->page.frame[PAGE_OLD_INFIMUM]); + ut_ad(cur->rec == &page[PAGE_OLD_INFIMUM]); } #endif rec_set_bit_field_1(insert_rec, 0, REC_OLD_N_OWNED, @@ -1609,11 +1637,11 @@ page_cur_insert_rec_low( rec_set_bit_field_2(insert_rec, heap_no, REC_OLD_HEAP_NO, REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT); memcpy(insert_rec - REC_NEXT, cur->rec - REC_NEXT, 2); - mach_write_to_2(cur->rec - REC_NEXT, page_offset(insert_rec)); + mach_write_to_2(cur->rec - REC_NEXT, insert_rec - page); while (!(n_owned= rec_get_n_owned_old(next_rec))) { - next_rec= block->page.frame + rec_get_next_offs(next_rec, false); - ut_ad(next_rec != block->page.frame); + next_rec= page + rec_get_next_offs(next_rec, false); + ut_ad(next_rec != page); } rec_set_bit_field_1(next_rec, n_owned + 1, REC_OLD_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); @@ -1625,8 +1653,7 @@ page_cur_insert_rec_low( ut_ad(extra_size > REC_N_OLD_EXTRA_BYTES); const byte * const c_start= cur->rec - extra_size; - if (c_start >= - &block->page.frame[PAGE_OLD_SUPREMUM_END + REC_N_OLD_EXTRA_BYTES]) + if (c_start >= &page[PAGE_OLD_SUPREMUM_END + REC_N_OLD_EXTRA_BYTES]) { /* Find common header bytes with the preceding record. */ const byte *r= rec - (REC_N_OLD_EXTRA_BYTES + 1); @@ -1644,7 +1671,7 @@ page_cur_insert_rec_low( const byte *r= rec; const byte *c= cur->rec; const byte *c_end= c + data_size; - if (page_rec_is_infimum(c) && data_size > 8) + if (page_rec_is_infimum(page, c) && data_size > 8) c_end= c + 8; static_assert(REC_N_OLD_EXTRA_BYTES == REC_N_NEW_EXTRA_BYTES + 1, ""); if (c <= insert_buf && c_end > insert_buf) @@ -1653,9 +1680,9 @@ page_cur_insert_rec_low( c_end >= next_rec - REC_N_OLD_EXTRA_BYTES + comp) c_end= next_rec - REC_N_OLD_EXTRA_BYTES + comp; else - c_end= std::min(c_end, block->page.frame + srv_page_size - + c_end= std::min(c_end, page + srv_page_size - PAGE_DIR - PAGE_DIR_SLOT_SIZE * - page_dir_get_n_slots(block->page.frame)); + page_dir_get_n_slots(page)); size_t data_common; /* Copy common data bytes of the preceding record. */ for (; c != c_end && *r == *c; c++, r++); @@ -1663,14 +1690,14 @@ page_cur_insert_rec_low( if (comp) mtr->page_insert(*block, reuse, - cur->rec - block->page.frame - PAGE_NEW_INFIMUM, + cur->rec - page - PAGE_NEW_INFIMUM, info_status, free_offset, hdr_common, data_common, insert_buf, extra_size - hdr_common - REC_N_NEW_EXTRA_BYTES, r, data_size - data_common); else mtr->page_insert(*block, reuse, - cur->rec - block->page.frame - PAGE_OLD_INFIMUM, + cur->rec - page - PAGE_OLD_INFIMUM, info_status, rec_get_n_fields_old(insert_rec) << 1 | rec_get_1byte_offs_flag(insert_rec), hdr_common, data_common, @@ -1689,20 +1716,19 @@ page_cur_insert_rec_low( if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) { - const ulint owner= page_dir_find_owner_slot(next_rec); + const ulint owner= page_dir_find_owner_slot(page, next_rec); if (UNIV_UNLIKELY(owner == ULINT_UNDEFINED)) { page_cur_directory_corrupted(*block, *index); return nullptr; } - if (page_dir_split_slot(*block, page_dir_get_nth_slot(block->page.frame, - owner))) + if (page_dir_split_slot(*block, page_dir_get_nth_slot(page, owner))) return nullptr; } rec_offs_make_valid(insert_buf + extra_size, index, - page_is_leaf(block->page.frame), offsets); + page_is_leaf(page), offsets); return insert_buf + extra_size; } @@ -1743,8 +1769,7 @@ static inline void page_zip_dir_add_slot(buf_block_t *block, if (const ulint len = ulint(stored - externs)) { memmove(dst, externs, len); - mtr->memmove(*block, dst - page_zip->data, externs - page_zip->data, - len); + mtr->zmemmove(*block, dst, externs, len); } } else @@ -1760,7 +1785,7 @@ static inline void page_zip_dir_add_slot(buf_block_t *block, { byte* dst = stored - PAGE_ZIP_DIR_SLOT_SIZE; memmove(dst, stored, len); - mtr->memmove(*block, dst - page_zip->data, stored - page_zip->data, len); + mtr->zmemmove(*block, dst, stored, len); } } @@ -1785,7 +1810,7 @@ page_cur_insert_rec_zip( mtr_t* mtr) /*!< in/out: mini-transaction */ { page_zip_des_t * const page_zip= page_cur_get_page_zip(cursor); - page_t * const page= cursor->block->page.frame; + page_t * const page= page_cur_get_page(cursor); dict_index_t * const index = cursor->index; ut_ad(page_zip); @@ -1857,7 +1882,7 @@ page_cur_insert_rec_zip( if (page_zip->m_nonempty || page_has_garbage(page)) { - ulint pos= page_rec_get_n_recs_before(cursor->rec); + ulint pos= page_rec_get_n_recs_before(page, cursor->rec); if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED)) return nullptr; @@ -1893,7 +1918,7 @@ page_cur_insert_rec_zip( if (insert_rec) { - ulint pos= page_rec_get_n_recs_before(insert_rec); + ulint pos= page_rec_get_n_recs_before(page, insert_rec); if (UNIV_UNLIKELY(!pos || pos == ULINT_UNDEFINED)) return nullptr; @@ -2038,18 +2063,19 @@ page_cur_insert_rec_zip( { use_heap: ut_ad(!free_rec); - insert_buf= page_mem_alloc_heap(cursor->block, rec_size, &heap_no); + insert_buf= page_mem_alloc_heap(cursor->block, page, rec_size, + &heap_no); if (UNIV_UNLIKELY(!insert_buf)) return insert_buf; static_assert(PAGE_N_HEAP == PAGE_HEAP_TOP + 2, "compatibility"); - mtr->memcpy(*cursor->block, PAGE_HEAP_TOP + PAGE_HEADER, 4); + mtr->memcpy(*cursor->block, PAGE_HEAP_TOP + PAGE_HEADER + page, 4); page_zip_dir_add_slot(cursor->block, index, mtr); } /* next record after current before the insertion */ - const rec_t *next_rec = page_rec_get_next_low(cursor->rec, TRUE); + const rec_t *next_rec = page_rec_get_next_low(page, cursor->rec, TRUE); if (UNIV_UNLIKELY(!next_rec || rec_get_status(next_rec) == REC_STATUS_INFIMUM || rec_get_status(cursor->rec) > REC_STATUS_INFIMUM)) @@ -2088,7 +2114,7 @@ page_cur_insert_rec_zip( ut_ad(!last_insert_rec || rec_get_node_ptr_flag(page + last_insert_rec) == rec_get_node_ptr_flag(insert_rec)); - mach_write_to_2(last_insert, page_offset(insert_rec)); + mach_write_to_2(last_insert, insert_rec - page); if (!index->is_spatial()) { @@ -2108,7 +2134,7 @@ page_cur_insert_rec_zip( inc_dir: mach_write_to_2(n, mach_read_from_2(n) + 1); } - else if (*dir != PAGE_RIGHT && page_rec_get_next(insert_rec) == + else if (*dir != PAGE_RIGHT && page_rec_get_next(page, insert_rec) == page + last_insert_rec) { *dir= PAGE_LEFT; @@ -2129,7 +2155,7 @@ page_cur_insert_rec_zip( ulint n_owned; while (!(n_owned= rec_get_n_owned_new(next_rec))) - if (!(next_rec= page_rec_get_next_low(next_rec, true))) + if (!(next_rec= page_rec_get_next_low(page, next_rec, true))) return nullptr; rec_set_bit_field_1(const_cast(next_rec), n_owned + 1, @@ -2142,13 +2168,13 @@ page_cur_insert_rec_zip( we have to split the corresponding directory slot in two. */ if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) { - const ulint owner= page_dir_find_owner_slot(next_rec); + const ulint owner= page_dir_find_owner_slot(page, next_rec); if (UNIV_UNLIKELY(owner == ULINT_UNDEFINED)) { page_cur_directory_corrupted(*cursor->block, *index); return nullptr; } - page_zip_dir_split_slot(cursor->block, owner, mtr); + page_zip_dir_split_slot(cursor->block, page, owner, mtr); } page_zip_write_rec(cursor->block, insert_rec, index, offsets, 1, mtr); @@ -2163,13 +2189,14 @@ page_cur_insert_rec_zip( static void page_mem_free(const buf_block_t &block, rec_t *rec, size_t data_size, size_t extra_size) { - ut_ad(page_align(rec) == block.page.frame); + page_t *page= block.page.frame; + ut_ad(page == page_align(rec)); ut_ad(!block.page.zip.data); - const rec_t *free= page_header_get_ptr(block.page.frame, PAGE_FREE); + const rec_t *free= page_header_get_ptr(page, PAGE_FREE); - const uint16_t n_heap= uint16_t(page_header_get_field(block.page.frame, + const uint16_t n_heap= uint16_t(page_header_get_field(page, PAGE_N_HEAP) - 1); - ut_ad(page_get_n_recs(block.page.frame) < (n_heap & 0x7fff)); + ut_ad(page_get_n_recs(page) < (n_heap & 0x7fff)); const bool deleting_top= n_heap == ((n_heap & 0x8000) ? (rec_get_heap_no_new(rec) | 0x8000) : rec_get_heap_no_old(rec)); @@ -2177,20 +2204,20 @@ static void page_mem_free(const buf_block_t &block, rec_t *rec, if (deleting_top) { byte *page_heap_top= my_assume_aligned<2>(PAGE_HEAP_TOP + PAGE_HEADER + - block.page.frame); + page); const uint16_t heap_top= mach_read_from_2(page_heap_top); - const size_t extra_savings= heap_top - page_offset(rec + data_size); + const size_t extra_savings= heap_top - (rec + data_size - page); ut_ad(extra_savings < heap_top); /* When deleting the last record, do not add it to the PAGE_FREE list. Instead, decrement PAGE_HEAP_TOP and PAGE_N_HEAP. */ - mach_write_to_2(page_heap_top, page_offset(rec - extra_size)); + mach_write_to_2(page_heap_top, rec - extra_size - page); mach_write_to_2(my_assume_aligned<2>(page_heap_top + 2), n_heap); static_assert(PAGE_N_HEAP == PAGE_HEAP_TOP + 2, "compatibility"); if (extra_savings) { byte *page_garbage= my_assume_aligned<2>(PAGE_GARBAGE + PAGE_HEADER + - block.page.frame); + page); uint16_t garbage= mach_read_from_2(page_garbage); ut_ad(garbage >= extra_savings); mach_write_to_2(page_garbage, garbage - extra_savings); @@ -2198,18 +2225,16 @@ static void page_mem_free(const buf_block_t &block, rec_t *rec, } else { - byte *page_free= my_assume_aligned<2>(PAGE_FREE + PAGE_HEADER + - block.page.frame); + byte *page_free= my_assume_aligned<2>(PAGE_FREE + PAGE_HEADER + page); byte *page_garbage= my_assume_aligned<2>(PAGE_GARBAGE + PAGE_HEADER + - block.page.frame); - mach_write_to_2(page_free, page_offset(rec)); + page); + mach_write_to_2(page_free, rec - page); mach_write_to_2(page_garbage, mach_read_from_2(page_garbage) + extra_size + data_size); } - memset_aligned<2>(PAGE_LAST_INSERT + PAGE_HEADER + block.page.frame, 0, 2); - byte *page_n_recs= my_assume_aligned<2>(PAGE_N_RECS + PAGE_HEADER + - block.page.frame); + memset_aligned<2>(PAGE_LAST_INSERT + PAGE_HEADER + page, 0, 2); + byte *page_n_recs= my_assume_aligned<2>(PAGE_N_RECS + PAGE_HEADER + page); mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) - 1); const byte* const end= rec + data_size; @@ -2219,7 +2244,7 @@ static void page_mem_free(const buf_block_t &block, rec_t *rec, uint16_t next= free ? ((n_heap & 0x8000) ? static_cast(free - rec) - : static_cast(free - block.page.frame)) + : static_cast(free - page)) : uint16_t{0}; mach_write_to_2(rec - REC_NEXT, next); } @@ -2249,46 +2274,48 @@ page_cur_delete_rec( /* page_zip_validate() will fail here when btr_cur_pessimistic_delete() invokes btr_set_min_rec_mark(). - Then, both "page_zip" and "block->page.frame" would have the + Then, both "page_zip" and "page" would have the min-rec-mark set on the smallest user record, but - "block->page.frame" would additionally have it set on the + "page" would additionally have it set on the smallest-but-one record. Because sloppy page_zip_validate_low() only ignores min-rec-flag differences in the smallest user record, it cannot be used here either. */ current_rec = cursor->rec; + page_t* const page = page_cur_get_page(cursor); const dict_index_t* const index = cursor->index; buf_block_t* const block = cursor->block; ut_ad(rec_offs_validate(current_rec, index, offsets)); - ut_ad(!!page_is_comp(block->page.frame) - == index->table->not_redundant()); - ut_ad(fil_page_index_page_check(block->page.frame)); - ut_ad(mach_read_from_8(PAGE_HEADER + PAGE_INDEX_ID + block->page.frame) - == index->id + ut_ad(!!page_is_comp(page) == index->table->not_redundant()); + ut_ad(fil_page_index_page_check(page)); + ut_ad(mach_read_from_8(PAGE_HEADER + PAGE_INDEX_ID + page) == index->id || mtr->is_inside_ibuf()); ut_ad(mtr->is_named_space(index->table->space)); /* The record must not be the supremum or infimum record. */ - ut_ad(page_rec_is_user_rec(current_rec)); + ut_ad(page_rec_is_user_rec(page, current_rec)); - if (page_get_n_recs(block->page.frame) == 1 + if (page_get_n_recs(page) == 1 && !rec_is_alter_metadata(current_rec, *index)) { /* Empty the page. */ - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_is_leaf(page)); /* Usually, this should be the root page, and the whole index tree should become empty. However, this could also be a call in btr_cur_pessimistic_update() to delete the only record in the page and to insert another one. */ - ut_ad(page_rec_is_supremum(page_rec_get_next(cursor->rec))); + ut_ad(page_rec_is_supremum(page, + page_rec_get_next(page, + cursor->rec))); page_cur_set_after_last(block, cursor); page_create_empty(page_cur_get_block(cursor), + page_cur_get_page(cursor), const_cast(index), mtr); return; } /* Save to local variables some data associated with current_rec */ - ulint cur_slot_no = page_dir_find_owner_slot(current_rec); + ulint cur_slot_no = page_dir_find_owner_slot(page, current_rec); if (UNIV_UNLIKELY(!cur_slot_no || cur_slot_no == ULINT_UNDEFINED)) { /* Avoid crashing due to a corrupted page. */ @@ -2296,8 +2323,8 @@ page_cur_delete_rec( return; } - cur_dir_slot = page_dir_get_nth_slot(block->page.frame, cur_slot_no); - cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot); + cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no); + cur_n_owned = page_dir_slot_get_n_owned(page, cur_dir_slot); /* The page gets invalid for btr_pcur_restore_pos(). We avoid invoking buf_block_modify_clock_inc(block) because its @@ -2309,14 +2336,15 @@ page_cur_delete_rec( left at the next record. */ rec = const_cast - (page_dir_slot_get_rec(cur_dir_slot + PAGE_DIR_SLOT_SIZE)); + (page_dir_slot_get_rec(page, + cur_dir_slot + PAGE_DIR_SLOT_SIZE)); /* rec now points to the record of the previous directory slot. Look for the immediate predecessor of current_rec in a loop. */ while (current_rec != rec) { prev_rec = rec; - if (!(rec = page_rec_get_next(rec))) { + if (!(rec = page_rec_get_next(page, rec))) { /* Avoid crashing due to a corrupted page. */ return; } @@ -2338,17 +2366,17 @@ page_cur_delete_rec( ut_ad(cur_n_owned > 1); rec_t* slot_rec = const_cast - (page_dir_slot_get_rec(cur_dir_slot)); + (page_dir_slot_get_rec(page, cur_dir_slot)); if (UNIV_LIKELY_NULL(block->page.zip.data)) { - ut_ad(page_is_comp(block->page.frame)); + ut_ad(page_is_comp(page)); if (current_rec == slot_rec) { page_zip_rec_set_owned(block, prev_rec, 1, mtr); page_zip_rec_set_owned(block, slot_rec, 0, mtr); slot_rec = prev_rec; - mach_write_to_2(cur_dir_slot, page_offset(slot_rec)); + mach_write_to_2(cur_dir_slot, slot_rec - page); } else if (cur_n_owned == 1 - && !page_rec_is_supremum(slot_rec)) { + && !page_rec_is_supremum(page, slot_rec)) { page_zip_rec_set_owned(block, slot_rec, 0, mtr); } @@ -2358,28 +2386,27 @@ page_cur_delete_rec( (slot_rec[-REC_NEW_N_OWNED] & ~REC_N_OWNED_MASK) | (cur_n_owned - 1) << REC_N_OWNED_SHIFT); - page_header_reset_last_insert(block, mtr); + page_header_reset_last_insert(block, page, mtr); page_zip_dir_delete(block, rec, index, offsets, - page_header_get_ptr(block->page.frame, - PAGE_FREE), + page_header_get_ptr(page, PAGE_FREE), mtr); if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) { - page_zip_dir_balance_slot(block, cur_slot_no, mtr); + page_zip_dir_balance_slot(block, page, cur_slot_no, + mtr); } return; } if (current_rec == slot_rec) { slot_rec = prev_rec; - mach_write_to_2(cur_dir_slot, page_offset(slot_rec)); + mach_write_to_2(cur_dir_slot, slot_rec - page); } const size_t data_size = rec_offs_data_size(offsets); const size_t extra_size = rec_offs_extra_size(offsets); - if (page_is_comp(block->page.frame)) { - mtr->page_delete(*block, page_offset(prev_rec) - - PAGE_NEW_INFIMUM, + if (page_is_comp(page)) { + mtr->page_delete(*block, prev_rec - page - PAGE_NEW_INFIMUM, extra_size - REC_N_NEW_EXTRA_BYTES, data_size); mach_write_to_2(prev_rec - REC_NEXT, static_cast @@ -2388,8 +2415,7 @@ page_cur_delete_rec( (slot_rec[-REC_NEW_N_OWNED] & ~REC_N_OWNED_MASK) | (cur_n_owned - 1) << REC_N_OWNED_SHIFT); } else { - mtr->page_delete(*block, page_offset(prev_rec) - - PAGE_OLD_INFIMUM); + mtr->page_delete(*block, prev_rec - page - PAGE_OLD_INFIMUM); memcpy(prev_rec - REC_NEXT, current_rec - REC_NEXT, 2); slot_rec[-REC_OLD_N_OWNED] = static_cast( (slot_rec[-REC_OLD_N_OWNED] & ~REC_N_OWNED_MASK) @@ -2403,12 +2429,12 @@ page_cur_delete_rec( slots. */ if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) { - page_dir_balance_slot(*block, cur_slot_no); + page_dir_balance_slot(*block, page, cur_slot_no); } - ut_ad(page_is_comp(block->page.frame) - ? page_simple_validate_new(block->page.frame) - : page_simple_validate_old(block->page.frame)); + ut_ad(page_is_comp(page) + ? page_simple_validate_new(page) + : page_simple_validate_old(page)); } /** Apply a INSERT_HEAP_REDUNDANT or INSERT_REUSE_REDUNDANT record that was @@ -2964,7 +2990,7 @@ bool page_apply_delete_redundant(const buf_block_t &block, ulint prev) page_mem_free(block, rec, data_size, extra_size); if (slot_owned < PAGE_DIR_SLOT_MIN_N_OWNED) - page_dir_balance_slot(block, (first_slot - slot) / 2); + page_dir_balance_slot(block, page, (first_slot - slot) / 2); ut_ad(page_simple_validate_old(page)); return false; @@ -3063,7 +3089,7 @@ bool page_apply_delete_dynamic(const buf_block_t &block, ulint prev, page_mem_free(block, rec, data_size, extra_size); if (slot_owned < PAGE_DIR_SLOT_MIN_N_OWNED) - page_dir_balance_slot(block, (first_slot - slot) / 2); + page_dir_balance_slot(block, page, (first_slot - slot) / 2); ut_ad(page_simple_validate_new(page)); return false; diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index 21b291e3a8b93..922e13c88c8af 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -80,94 +80,33 @@ Assuming a page size of 8 kB, a typical index page of a secondary index contains 300 index entries, and the size of the page directory is 50 x 4 bytes = 200 bytes. */ -/***************************************************************//** -Looks for the directory slot which owns the given record. -@return the directory slot number -@retval ULINT_UNDEFINED on corruption */ -ulint -page_dir_find_owner_slot( -/*=====================*/ - const rec_t* rec) /*!< in: the physical record */ -{ - ut_ad(page_rec_check(rec)); - - const page_t* page = page_align(rec); - const page_dir_slot_t* first_slot = page_dir_get_nth_slot(page, 0); - const page_dir_slot_t* slot = page_dir_get_nth_slot( - page, ulint(page_dir_get_n_slots(page)) - 1); - const rec_t* r = rec; - - if (page_is_comp(page)) { - while (rec_get_n_owned_new(r) == 0) { - r = page_rec_get_next_low(r, true); - if (UNIV_UNLIKELY(r < page + PAGE_NEW_SUPREMUM - || r >= slot)) { - return ULINT_UNDEFINED; - } - } - } else { - while (rec_get_n_owned_old(r) == 0) { - r = page_rec_get_next_low(r, false); - if (UNIV_UNLIKELY(r < page + PAGE_OLD_SUPREMUM - || r >= slot)) { - return ULINT_UNDEFINED; - } - } - } - - while (UNIV_LIKELY(*(uint16*) slot - != mach_encode_2(ulint(r - page)))) { - if (UNIV_UNLIKELY(slot == first_slot)) { - return ULINT_UNDEFINED; - } - - slot += PAGE_DIR_SLOT_SIZE; - } - - return(((ulint) (first_slot - slot)) / PAGE_DIR_SLOT_SIZE); -} - /**************************************************************//** Used to check the consistency of a directory slot. @return TRUE if succeed */ -static -ibool -page_dir_slot_check( -/*================*/ - const page_dir_slot_t* slot) /*!< in: slot */ +static bool page_dir_slot_check(const page_t *page, + const page_dir_slot_t *slot) { - const page_t* page; - ulint n_slots; - ulint n_owned; + ulint n_slots= page_dir_get_n_slots(page); - ut_a(slot); + if (slot > page_dir_get_nth_slot(page, 0) || + slot < page_dir_get_nth_slot(page, n_slots - 1)) + return false; - page = page_align(slot); - - n_slots = page_dir_get_n_slots(page); + const rec_t *rec= page_dir_slot_get_rec_validate(page, slot); + if (!rec || !page_rec_check(page, rec)) + return false; - ut_a(slot <= page_dir_get_nth_slot(page, 0)); - ut_a(slot >= page_dir_get_nth_slot(page, n_slots - 1)); + ulint n_owned= page_is_comp(page) + ? rec_get_n_owned_new(rec) + : rec_get_n_owned_old(rec); - ut_a(page_rec_check(page_dir_slot_get_rec(slot))); + if (slot == page_dir_get_nth_slot(page, 0)) + return n_owned == 1; + if (slot == page_dir_get_nth_slot(page, n_slots - 1)) + return n_owned >= 1 && n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED; - if (page_is_comp(page)) { - n_owned = rec_get_n_owned_new(page_dir_slot_get_rec(slot)); - } else { - n_owned = rec_get_n_owned_old(page_dir_slot_get_rec(slot)); - } - - if (slot == page_dir_get_nth_slot(page, 0)) { - ut_a(n_owned == 1); - } else if (slot == page_dir_get_nth_slot(page, n_slots - 1)) { - ut_a(n_owned >= 1); - ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED); - } else { - ut_a(n_owned >= PAGE_DIR_SLOT_MIN_N_OWNED); - ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED); - } - - return(TRUE); + return n_owned >= PAGE_DIR_SLOT_MIN_N_OWNED && + n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED; } /*************************************************************//** @@ -176,6 +115,7 @@ void page_set_max_trx_id( /*================*/ buf_block_t* block, /*!< in/out: page */ + page_t* page, /*!< in/out: page frame */ page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ trx_id_t trx_id, /*!< in: transaction id */ mtr_t* mtr) /*!< in/out: mini-transaction, or NULL */ @@ -183,8 +123,7 @@ page_set_max_trx_id( ut_ad(!mtr || mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); ut_ad(!page_zip || page_zip == &block->page.zip); static_assert((PAGE_HEADER + PAGE_MAX_TRX_ID) % 8 == 0, "alignment"); - byte *max_trx_id= my_assume_aligned<8>(PAGE_MAX_TRX_ID + - PAGE_HEADER + block->page.frame); + byte *max_trx_id= my_assume_aligned<8>(PAGE_MAX_TRX_ID + PAGE_HEADER + page); mtr->write<8>(*block, max_trx_id, trx_id); if (UNIV_LIKELY_NULL(page_zip)) @@ -194,7 +133,6 @@ page_set_max_trx_id( /** Persist the AUTO_INCREMENT value on a clustered index root page. @param[in,out] block clustered index root page -@param[in] index clustered index @param[in] autoinc next available AUTO_INCREMENT value @param[in,out] mtr mini-transaction @param[in] reset whether to reset the AUTO_INCREMENT @@ -256,8 +194,9 @@ static const byte infimum_supremum_compact[] = { /** Create an index page. @param[in,out] block buffer block -@param[in] comp nonzero=compact page format */ -void page_create_low(const buf_block_t* block, bool comp) +@param[in] comp nonzero=compact page format +@return page frame */ +page_t* page_create_low(const buf_block_t* block, bool comp) { page_t* page; @@ -301,17 +240,20 @@ void page_create_low(const buf_block_t* block, bool comp) page[srv_page_size - PAGE_DIR - PAGE_DIR_SLOT_SIZE + 1] = PAGE_OLD_INFIMUM; } + + return page; } /** Create an uncompressed index page. @param[in,out] block buffer block @param[in,out] mtr mini-transaction -@param[in] comp set unless ROW_FORMAT=REDUNDANT */ -void page_create(buf_block_t *block, mtr_t *mtr, bool comp) +@param[in] comp set unless ROW_FORMAT=REDUNDANT +@return page frame */ +page_t *page_create(buf_block_t *block, mtr_t *mtr, bool comp) { mtr->page_create(*block, comp); buf_block_modify_clock_inc(block); - page_create_low(block, comp); + return page_create_low(block, comp); } /**********************************************************//** @@ -350,18 +292,16 @@ page_create_zip( || index->table->is_temporary()); buf_block_modify_clock_inc(block); - page_create_low(block, true); + page_t* page = page_create_low(block, true); if (index->is_spatial()) { - mach_write_to_2(FIL_PAGE_TYPE + block->page.frame, - FIL_PAGE_RTREE); - memset(block->page.frame + FIL_RTREE_SPLIT_SEQ_NUM, 0, 8); + mach_write_to_2(FIL_PAGE_TYPE + page, FIL_PAGE_RTREE); + memset(page + FIL_RTREE_SPLIT_SEQ_NUM, 0, 8); memset(block->page.zip.data + FIL_RTREE_SPLIT_SEQ_NUM, 0, 8); } - mach_write_to_2(PAGE_HEADER + PAGE_LEVEL + block->page.frame, level); - mach_write_to_8(PAGE_HEADER + PAGE_MAX_TRX_ID + block->page.frame, - max_trx_id); + mach_write_to_2(PAGE_HEADER + PAGE_LEVEL + page, level); + mach_write_to_8(PAGE_HEADER + PAGE_MAX_TRX_ID + page, max_trx_id); if (!page_zip_compress(block, index, page_zip_level, mtr)) { /* The compression of a newly created @@ -376,13 +316,14 @@ void page_create_empty( /*==============*/ buf_block_t* block, /*!< in/out: B-tree block */ + page_t* page, /*!< in: block page frame */ dict_index_t* index, /*!< in: the index of the page */ mtr_t* mtr) /*!< in/out: mini-transaction */ { trx_id_t max_trx_id; page_zip_des_t* page_zip= buf_block_get_page_zip(block); - ut_ad(fil_page_index_page_check(block->page.frame)); + ut_ad(fil_page_index_page_check(page)); ut_ad(!index->is_dummy); ut_ad(block->page.id().space() == index->table->space->id); @@ -392,12 +333,12 @@ page_create_empty( for MVCC. */ if (dict_index_is_sec_or_ibuf(index) && !index->table->is_temporary() - && page_is_leaf(block->page.frame)) { - max_trx_id = page_get_max_trx_id(block->page.frame); + && page_is_leaf(page)) { + max_trx_id = page_get_max_trx_id(page); ut_ad(max_trx_id); } else if (block->page.id().page_no() == index->page) { /* Preserve PAGE_ROOT_AUTO_INC. */ - max_trx_id = page_get_max_trx_id(block->page.frame); + max_trx_id = page_get_max_trx_id(page); } else { max_trx_id = 0; } @@ -405,8 +346,7 @@ page_create_empty( if (page_zip) { ut_ad(!index->table->is_temporary()); page_create_zip(block, index, - page_header_get_field(block->page.frame, - PAGE_LEVEL), + page_header_get_field(page, PAGE_LEVEL), max_trx_id, mtr); } else { page_create(block, mtr, index->table->not_redundant()); @@ -415,18 +355,18 @@ page_create_empty( | byte(FIL_PAGE_RTREE)) == FIL_PAGE_RTREE, "compatibility"); mtr->write<1>(*block, - FIL_PAGE_TYPE + 1 + block->page.frame, + FIL_PAGE_TYPE + 1 + page, byte(FIL_PAGE_RTREE)); - if (mach_read_from_8(block->page.frame - + FIL_RTREE_SPLIT_SEQ_NUM)) { - mtr->memset(block, FIL_RTREE_SPLIT_SEQ_NUM, + if (mach_read_from_8(page + FIL_RTREE_SPLIT_SEQ_NUM)) { + mtr->memset(block, + page + FIL_RTREE_SPLIT_SEQ_NUM, 8, 0); } } if (max_trx_id) { mtr->write<8>(*block, PAGE_HEADER + PAGE_MAX_TRX_ID - + block->page.frame, max_trx_id); + + page, max_trx_id); } } } @@ -450,7 +390,7 @@ page_copy_rec_list_end_no_locks( dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr) /*!< in: mtr */ { - page_t* new_page = buf_block_get_frame(new_block); + page_t* new_page = new_block->page.frame; page_cur_t cur1; page_cur_t cur2; mem_heap_t* heap = NULL; @@ -472,9 +412,7 @@ page_copy_rec_list_end_no_locks( return DB_CORRUPTION; } - const ulint n_core = page_is_leaf(block->page.frame) - ? index->n_core_fields : 0; - + const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0; dberr_t err = DB_SUCCESS; page_cur_set_before_first(new_block, &cur2); @@ -527,8 +465,7 @@ page_copy_rec_list_end( page_t* new_page = new_block->page.frame; page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block); page_t* page = block->page.frame; - rec_t* ret = page_rec_get_next( - page_get_infimum_rec(new_page)); + rec_t* ret = page_rec_get_first(new_page); ulint num_moved = 0; ut_ad(page_align(rec) == page); @@ -549,7 +486,7 @@ page_copy_rec_list_end( ut_a(page_zip_validate_low(page_zip, page, index, TRUE)); } #endif /* UNIV_ZIP_DEBUG */ - ut_ad(buf_block_get_frame(block) == page); + ut_ad(block->page.frame == page); ut_ad(page_is_leaf(page) == page_is_leaf(new_page)); ut_ad(page_is_comp(page) == page_is_comp(new_page)); /* Here, "ret" may be pointing to a user record or the @@ -566,8 +503,7 @@ page_copy_rec_list_end( rtr_rec_move_t* rec_move = nullptr; if (index->is_spatial()) { - ulint max_to_move = page_get_n_recs( - buf_block_get_frame(block)); + ulint max_to_move = page_get_n_recs(page); heap = mem_heap_create(256); rec_move= static_cast( mem_heap_alloc(heap, max_to_move * sizeof *rec_move)); @@ -621,7 +557,7 @@ page_copy_rec_list_end( /* Before trying to reorganize the page, store the number of preceding records on the page. */ ulint ret_pos - = page_rec_get_n_recs_before(ret); + = page_rec_get_n_recs_before(new_page, ret); /* Before copying, "ret" was the successor of the predefined infimum record. It must still have at least one predecessor (the predefined @@ -696,7 +632,8 @@ page_copy_rec_list_start( { ut_ad(page_align(rec) == block->page.frame); - page_t* new_page = buf_block_get_frame(new_block); + const page_t* page = block->page.frame; + page_t* new_page = new_block->page.frame; page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block); page_cur_t cur1; page_cur_t cur2; @@ -704,7 +641,7 @@ page_copy_rec_list_start( ulint num_moved = 0; rtr_rec_move_t* rec_move = NULL; rec_t* ret - = page_rec_get_prev(page_get_supremum_rec(new_page)); + = page_rec_get_prev(new_page, page_get_supremum_rec(new_page)); rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; rec_offs_init(offsets_); @@ -718,7 +655,7 @@ page_copy_rec_list_start( /* Here, "ret" may be pointing to a user record or the predefined infimum record. */ - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(page, rec)) { *err = DB_SUCCESS; return(ret); } @@ -737,13 +674,12 @@ page_copy_rec_list_start( cur2.index = index; page_cur_position(ret, new_block, &cur2); - const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0; + const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; /* Copy records from the original page to the new page */ if (index->is_spatial()) { ut_ad(!index->is_instant()); - ulint max_to_move = page_get_n_recs( - buf_block_get_frame(block)); + ulint max_to_move = page_get_n_recs(page_align(rec)); heap = mem_heap_create(256); rec_move = static_cast(mem_heap_alloc( @@ -805,7 +741,8 @@ page_copy_rec_list_start( #endif /* DBUG_OFF */ /* Before trying to reorganize the page, store the number of preceding records on the page. */ - ulint ret_pos = page_rec_get_n_recs_before(ret); + ulint ret_pos = page_rec_get_n_recs_before(new_page, + ret); /* Before copying, "ret" was the predecessor of the predefined supremum record. If it was the predefined infimum record, then it would @@ -877,35 +814,33 @@ page_delete_rec_list_end( mtr_t* mtr) /*!< in: mtr */ { page_t * const page= block->page.frame; - ut_ad(size == ULINT_UNDEFINED || size < srv_page_size); - ut_ad(page_align(rec) == page); ut_ad(index->table->not_redundant() == !!page_is_comp(page)); #ifdef UNIV_ZIP_DEBUG ut_a(!block->page.zip.data || page_zip_validate(&block->page.zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ - if (page_rec_is_supremum(rec)) + if (page_rec_is_supremum(page, rec)) { ut_ad(n_recs == 0 || n_recs == ULINT_UNDEFINED); /* Nothing to do, there are no records bigger than the page supremum. */ return DB_SUCCESS; } - if (page_rec_is_infimum(rec) || + if (page_rec_is_infimum(page, rec) || n_recs == page_get_n_recs(page) || rec == (page_is_comp(page) - ? page_rec_get_next_low(page + PAGE_NEW_INFIMUM, 1) - : page_rec_get_next_low(page + PAGE_OLD_INFIMUM, 0))) + ? page_rec_get_next_low(page, page + PAGE_NEW_INFIMUM, 1) + : page_rec_get_next_low(page, page + PAGE_OLD_INFIMUM, 0))) { /* We are deleting all records. */ - page_create_empty(block, index, mtr); + page_create_empty(block, page, index, mtr); return DB_SUCCESS; } #if 0 // FIXME: consider deleting the last record as a special case - if (page_rec_is_last(rec)) + if (page_rec_is_last(page, rec)) { page_cur_t cursor= { index, rec, offsets, block }; page_cur_delete_rec(&cursor, index, offsets, mtr); @@ -933,13 +868,13 @@ page_delete_rec_list_end( cur.index= index; offsets= rec_get_offsets(rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); - rec= const_cast(page_rec_get_next_low(rec, true)); + rec= const_cast(page_rec_get_next_low(page, rec, true)); #ifdef UNIV_ZIP_DEBUG ut_a(page_zip_validate(&block->page.zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ page_cur_delete_rec(&cur, offsets, mtr); } - while (page_offset(rec) != PAGE_NEW_SUPREMUM); + while (rec != &page[PAGE_NEW_SUPREMUM]); if (UNIV_LIKELY_NULL(heap)) mem_heap_free(heap); @@ -947,10 +882,10 @@ page_delete_rec_list_end( } #endif - byte *prev_rec= page_rec_get_prev(rec); + byte *prev_rec= page_rec_get_prev(page, rec); if (UNIV_UNLIKELY(!prev_rec)) return DB_CORRUPTION; - byte *last_rec= page_rec_get_prev(page_get_supremum_rec(page)); + byte *last_rec= page_rec_get_prev(page, page_get_supremum_rec(page)); if (UNIV_UNLIKELY(!last_rec)) return DB_CORRUPTION; @@ -976,11 +911,11 @@ page_delete_rec_list_end( n_recs++; if (scrub) - mtr->memset(block, page_offset(rec2), rec_offs_data_size(offsets), 0); + mtr->memset(block, rec2, rec_offs_data_size(offsets), 0); - rec2= page_rec_get_next(rec2); + rec2= page_rec_get_next(page, rec2); } - while (rec2 && !page_rec_is_supremum(rec2)); + while (rec2 && !page_rec_is_supremum(page, rec2)); if (UNIV_LIKELY_NULL(heap)) mem_heap_free(heap); @@ -1000,20 +935,20 @@ page_delete_rec_list_end( while (!(n_owned= rec_get_n_owned_new(owner_rec))) { count++; - if (!(owner_rec= page_rec_get_next_low(owner_rec, true))) + if (!(owner_rec= page_rec_get_next_low(page, owner_rec, true))) return DB_CORRUPTION; } else while (!(n_owned= rec_get_n_owned_old(owner_rec))) { count++; - if (!(owner_rec= page_rec_get_next_low(owner_rec, false))) + if (!(owner_rec= page_rec_get_next_low(page, owner_rec, false))) return DB_CORRUPTION; } ut_ad(n_owned > count); n_owned-= count; - slot_index= page_dir_find_owner_slot(owner_rec); + slot_index= page_dir_find_owner_slot(page, owner_rec); } if (UNIV_UNLIKELY(!slot_index || slot_index == ULINT_UNDEFINED)) @@ -1030,7 +965,7 @@ page_delete_rec_list_end( const uint16_t free= page_header_get_field(page, PAGE_FREE); static_assert(PAGE_FREE + 2 == PAGE_GARBAGE, "compatibility"); - mach_write_to_2(page_header, page_offset(rec)); + mach_write_to_2(page_header, rec - page); mach_write_to_2(my_assume_aligned<2>(page_header + 2), mach_read_from_2(my_assume_aligned<2>(page_free + 2)) + size); @@ -1060,19 +995,17 @@ page_delete_rec_list_end( PAGE_N_RECS + 2 - PAGE_N_DIR_SLOTS); // TODO: the equivalent of page_zip_dir_delete() for all records mach_write_to_2(prev_rec - REC_NEXT, static_cast - (PAGE_NEW_SUPREMUM - page_offset(prev_rec))); - mach_write_to_2(last_rec - REC_NEXT, free - ? static_cast(free - page_offset(last_rec)) - : 0U); + (PAGE_NEW_SUPREMUM - prev_rec - page)); + mach_write_to_2(last_rec - REC_NEXT, + free ? uint16(free - (last_rec - page)) : 0U); return DB_SUCCESS; } #endif mtr->write<1,mtr_t::MAYBE_NOP>(*block, owned, new_owned); - mtr->write<2>(*block, prev_rec - REC_NEXT, static_cast - (PAGE_NEW_SUPREMUM - page_offset(prev_rec))); + mtr->write<2>(*block, prev_rec - REC_NEXT, + uint16_t(PAGE_NEW_SUPREMUM - (prev_rec - page))); mtr->write<2>(*block, last_rec - REC_NEXT, free - ? static_cast(free - page_offset(last_rec)) - : 0U); + ? uint16_t(free - (last_rec - page)) : 0U); } else { @@ -1103,16 +1036,15 @@ page_delete_rec_list_start( rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; mem_heap_t* heap = NULL; + page_t* page = block->page.frame; rec_offs_init(offsets_); - ut_ad(page_align(rec) == block->page.frame); - ut_ad((ibool) !!page_rec_is_comp(rec) + ut_ad((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table)); #ifdef UNIV_ZIP_DEBUG { page_zip_des_t* page_zip= buf_block_get_page_zip(block); - page_t* page = buf_block_get_frame(block); /* page_zip_validate() would detect a min_rec_mark mismatch in btr_page_split_and_insert() @@ -1124,13 +1056,13 @@ page_delete_rec_list_start( } #endif /* UNIV_ZIP_DEBUG */ - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(page, rec)) { return; } - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { /* We are deleting all records. */ - page_create_empty(block, index, mtr); + page_create_empty(block, block->page.frame, index, mtr); return; } @@ -1141,7 +1073,7 @@ page_delete_rec_list_start( return; } - const ulint n_core = page_rec_is_leaf(rec) + const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; while (page_cur_get_rec(&cur1) != rec) { @@ -1180,7 +1112,7 @@ page_rec_get_nth_const( for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); - n_owned = page_dir_slot_get_n_owned(slot); + n_owned = page_dir_slot_get_n_owned(page, slot); if (n_owned > nth) { break; @@ -1192,15 +1124,15 @@ page_rec_get_nth_const( if (UNIV_UNLIKELY(!i)) { return nullptr; } - rec = page_dir_slot_get_rec(slot + 2); + rec = page_dir_slot_get_rec(page, slot + 2); if (page_is_comp(page)) { do { - rec = page_rec_get_next_low(rec, TRUE); + rec = page_rec_get_next_low(page, rec, TRUE); } while (rec && nth--); } else { do { - rec = page_rec_get_next_low(rec, FALSE); + rec = page_rec_get_next_low(page, rec, FALSE); } while (rec && nth--); } @@ -1208,34 +1140,28 @@ page_rec_get_nth_const( } -/************************************************************//** -Gets the pointer to the previous record. +/** Get the previous record on a page. +@param page index page +@param rec record in the page (not page infimum) @return pointer to previous record @retval nullptr on error */ -const rec_t* -page_rec_get_prev_const( -/*====================*/ - const rec_t* rec) /*!< in: pointer to record, must not be page - infimum */ +rec_t* page_rec_get_prev(page_t *page, const rec_t *rec) { - const rec_t* rec2; - const rec_t* prev_rec = NULL; - - ut_ad(page_rec_check(rec)); - - const page_t* const page = page_align(rec); + ut_ad(page_rec_check(page, rec)); - ut_ad(!page_rec_is_infimum(rec)); + ut_ad(!page_rec_is_infimum(page, rec)); - ulint slot_no = page_dir_find_owner_slot(rec); + ulint slot_no = page_dir_find_owner_slot(page, rec); if (UNIV_UNLIKELY(!slot_no || slot_no == ULINT_UNDEFINED)) { return nullptr; } const page_dir_slot_t* slot = page_dir_get_nth_slot(page, slot_no - 1); + rec_t* rec2 = page_dir_slot_get_rec_validate(page, slot); + rec_t* prev_rec = nullptr; - if (UNIV_UNLIKELY(!(rec2 = page_dir_slot_get_rec_validate(slot)))) { + if (UNIV_UNLIKELY(!rec2)) { return nullptr; } @@ -1284,28 +1210,28 @@ page_rec_get_prev_const( } /** Return the number of preceding records in an index page. -@param rec index record +@param page index page +@param rec index record @return number of preceding records, including the infimum pseudo-record @retval ULINT_UNDEFINED on corrupted page */ -ulint page_rec_get_n_recs_before(const rec_t *rec) +ulint page_rec_get_n_recs_before(const page_t *page, const rec_t *rec) { - const page_t *const page= page_align(rec); const page_dir_slot_t *slot = page_dir_get_nth_slot(page, 0); const page_dir_slot_t *const end_slot= slot - 2 * page_dir_get_n_slots(page); lint n= 0; - ut_ad(page_rec_check(rec)); + ut_ad(page_rec_check(page, rec)); if (page_is_comp(page)) { for (; rec_get_n_owned_new(rec) == 0; n--) - if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(rec, true)))) + if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(page, rec, true)))) return ULINT_UNDEFINED; do { - const rec_t *slot_rec= page_dir_slot_get_rec_validate(slot); + const rec_t *slot_rec= page_dir_slot_get_rec_validate(page, slot); if (UNIV_UNLIKELY(!slot_rec)) break; n+= lint(rec_get_n_owned_new(slot_rec)); @@ -1318,12 +1244,12 @@ ulint page_rec_get_n_recs_before(const rec_t *rec) else { for (; rec_get_n_owned_old(rec) == 0; n--) - if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(rec, false)))) + if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(page, rec, false)))) return ULINT_UNDEFINED; do { - const rec_t *slot_rec= page_dir_slot_get_rec_validate(slot); + const rec_t *slot_rec= page_dir_slot_get_rec_validate(page, slot); if (UNIV_UNLIKELY(!slot_rec)) break; n+= lint(rec_get_n_owned_old(slot_rec)); @@ -1342,15 +1268,17 @@ ulint page_rec_get_n_recs_before(const rec_t *rec) /************************************************************//** Prints record contents including the data relevant only in the index page context. */ +ATTRIBUTE_COLD void page_rec_print( /*===========*/ const rec_t* rec, /*!< in: physical record */ const rec_offs* offsets)/*!< in: record descriptor */ { - ut_a(!page_rec_is_comp(rec) == !rec_offs_comp(offsets)); + const page_t* const page = page_align(rec); + ut_a(!page_is_comp(page) == !rec_offs_comp(offsets)); rec_print_new(stderr, rec, offsets); - if (page_rec_is_comp(rec)) { + if (page_is_comp(page)) { ib::info() << "n_owned: " << rec_get_n_owned_new(rec) << "; heap_no: " << rec_get_heap_no_new(rec) << "; next rec: " << rec_get_next_offs(rec, TRUE); @@ -1360,7 +1288,7 @@ page_rec_print( << "; next rec: " << rec_get_next_offs(rec, FALSE); } - page_rec_check(rec); + ut_a(page_rec_check(page, rec)); rec_validate(rec, offsets); } @@ -1368,6 +1296,7 @@ page_rec_print( /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ +ATTRIBUTE_COLD void page_dir_print( /*===========*/ @@ -1383,9 +1312,8 @@ page_dir_print( fprintf(stderr, "--------------------------------\n" "PAGE DIRECTORY\n" "Page address %p\n" - "Directory stack top at offs: %lu; number of slots: %lu\n", - page, (ulong) page_offset(page_dir_get_nth_slot(page, n - 1)), - (ulong) n); + "Directory stack top at offs: %zu; number of slots: %zu\n", + page, page_dir_get_nth_slot(page, n - 1) - page, n); for (i = 0; i < n; i++) { slot = page_dir_get_nth_slot(page, i); if ((i == pr_n) && (i < n - pr_n)) { @@ -1394,21 +1322,21 @@ page_dir_print( if ((i < pr_n) || (i >= n - pr_n)) { fprintf(stderr, "Contents of slot: %lu: n_owned: %lu," - " rec offs: %lu\n", - (ulong) i, - (ulong) page_dir_slot_get_n_owned(slot), - (ulong) - page_offset(page_dir_slot_get_rec(slot))); + " rec offs: %zu\n", + i, + page_dir_slot_get_n_owned(slot), + page_dir_slot_get_rec(page, slot) - page); } } - fprintf(stderr, "Total of %lu records\n" + fprintf(stderr, "Total of %u records\n" "--------------------------------\n", - (ulong) (PAGE_HEAP_NO_USER_LOW + page_get_n_recs(page))); + unsigned(PAGE_HEAP_NO_USER_LOW + page_get_n_recs(page))); } /***************************************************************//** This is used to print the contents of the page record list for debugging purposes. */ +ATTRIBUTE_COLD void page_print_list( /*============*/ @@ -1480,6 +1408,7 @@ page_print_list( /***************************************************************//** Prints the info in a page header. */ +ATTRIBUTE_COLD void page_header_print( /*==============*/ @@ -1507,6 +1436,7 @@ page_header_print( /***************************************************************//** This is used to print the contents of the page for debugging purposes. */ +ATTRIBUTE_COLD void page_print( /*=======*/ @@ -1543,10 +1473,11 @@ page_rec_validate( page = page_align(rec); ut_a(!page_is_comp(page) == !rec_offs_comp(offsets)); - page_rec_check(rec); + if (!page_rec_check(page, rec)) + return false; rec_validate(rec, offsets); - if (page_rec_is_comp(rec)) { + if (page_is_comp(page)) { n_owned = rec_get_n_owned_new(rec); heap_no = rec_get_heap_no_new(rec); } else { @@ -1555,13 +1486,13 @@ page_rec_validate( } if (UNIV_UNLIKELY(!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED))) { - ib::warn() << "Dir slot of rec " << page_offset(rec) + ib::warn() << "Dir slot of rec " << rec - page << ", n owned too big " << n_owned; return(FALSE); } if (UNIV_UNLIKELY(!(heap_no < page_dir_get_n_heap(page)))) { - ib::warn() << "Heap no of rec " << page_offset(rec) + ib::warn() << "Heap no of rec " << rec - page << " too big " << heap_no << " " << page_dir_get_n_heap(page); return(FALSE); @@ -1643,8 +1574,7 @@ page_simple_validate_old( << "Record heap and dir overlap on a page, heap top " << page_header_get_field(page, PAGE_HEAP_TOP) << ", dir " - << page_offset(page_dir_get_nth_slot(page, - n_slots - 1)); + << page_dir_get_nth_slot(page, n_slots - 1) - page; goto func_exit; } @@ -1682,7 +1612,7 @@ page_simple_validate_old( } if (UNIV_UNLIKELY - (page_dir_slot_get_rec(slot) != rec)) { + (page_dir_slot_get_rec(page, slot) != rec)) { ib::error() << "Dir slot does not point" " to right rec " << (rec - page); @@ -1691,13 +1621,13 @@ page_simple_validate_old( own_count = 0; - if (!page_rec_is_supremum(rec)) { + if (!page_rec_is_supremum(page, rec)) { slot_no++; slot = page_dir_get_nth_slot(page, slot_no); } } - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { break; } @@ -1721,7 +1651,7 @@ page_simple_validate_old( goto func_exit; } - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); own_count++; } @@ -1842,8 +1772,8 @@ page_simple_validate_new( ib::error() << "Record heap and dir overlap on a page," " heap top " << page_header_get_field(page, PAGE_HEAP_TOP) - << ", dir " << page_offset( - page_dir_get_nth_slot(page, n_slots - 1)); + << ", dir " + << page_dir_get_nth_slot(page, n_slots - 1) - page; goto func_exit; } @@ -1861,9 +1791,9 @@ page_simple_validate_new( for (;;) { if (UNIV_UNLIKELY(rec < page + PAGE_NEW_INFIMUM || rec > rec_heap_top)) { - ib::error() << "Record " << page_offset(rec) + ib::error() << "Record " << rec - page << " is out of bounds: " - << page_offset(rec_heap_top); + << rec_heap_top - page; goto func_exit; } @@ -1875,28 +1805,28 @@ page_simple_validate_new( ib::error() << "Wrong owned count " << rec_get_n_owned_new(rec) << ", " << own_count << ", rec " - << page_offset(rec); + << rec - page; goto func_exit; } if (UNIV_UNLIKELY - (page_dir_slot_get_rec(slot) != rec)) { + (page_dir_slot_get_rec(page, slot) != rec)) { ib::error() << "Dir slot does not point" - " to right rec " << page_offset(rec); + " to right rec " << rec - page; goto func_exit; } own_count = 0; - if (!page_rec_is_supremum(rec)) { + if (!page_rec_is_supremum(page, rec)) { slot_no++; slot = page_dir_get_nth_slot(page, slot_no); } } - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { break; } @@ -1907,7 +1837,7 @@ page_simple_validate_new( ib::error() << "Next record offset nonsensical " << rec_get_next_offs(rec, TRUE) - << " for rec " << page_offset(rec); + << " for rec " << rec - page; goto func_exit; } @@ -1920,7 +1850,7 @@ page_simple_validate_new( goto func_exit; } - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); own_count++; } @@ -1954,15 +1884,15 @@ page_simple_validate_new( || rec >= page + srv_page_size)) { ib::error() << "Free list record has" - " a nonsensical offset " << page_offset(rec); + " a nonsensical offset " << rec - page; goto func_exit; } if (UNIV_UNLIKELY(rec > rec_heap_top)) { - ib::error() << "Free list record " << page_offset(rec) + ib::error() << "Free list record " << rec - page << " is above rec heap top " - << page_offset(rec_heap_top); + << rec_heap_top - page; goto func_exit; } @@ -2130,7 +2060,7 @@ bool page_validate(const page_t* page, const dict_index_t* index) offsets = rec_get_offsets(rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); - if (page_is_comp(page) && page_rec_is_user_rec(rec) + if (page_is_comp(page) && page_rec_is_user_rec(page, rec) && UNIV_UNLIKELY(rec_get_node_ptr_flag(rec) == page_is_leaf(page))) { ib::error() << "'node_ptr' flag mismatch"; @@ -2193,14 +2123,14 @@ bool page_validate(const page_t* page, const dict_index_t* index) ib::error() << "impossible record status " << status; ret = false; - } else if (page_rec_is_infimum(rec)) { + } else if (page_rec_is_infimum(page, rec)) { if (status != REC_STATUS_INFIMUM) { ib::error() << "infimum record has status " << status; ret = false; } - } else if (page_rec_is_supremum(rec)) { + } else if (page_rec_is_supremum(page, rec)) { if (status != REC_STATUS_SUPREMUM) { ib::error() << "supremum record has " "status " @@ -2224,7 +2154,7 @@ bool page_validate(const page_t* page, const dict_index_t* index) /* Check that the records are in the ascending order */ if (count >= PAGE_HEAP_NO_USER_LOW - && !page_rec_is_supremum(rec)) { + && !page_rec_is_supremum(page, rec)) { int ret = cmp_rec_rec( rec, old_rec, offsets, old_offsets, index); @@ -2259,7 +2189,7 @@ bool page_validate(const page_t* page, const dict_index_t* index) } } - if (page_rec_is_user_rec(rec)) { + if (page_rec_is_user_rec(page, rec)) { data_size += rec_offs_size(offsets); @@ -2272,7 +2202,7 @@ bool page_validate(const page_t* page, const dict_index_t* index) #endif /* UNIV_GIS_DEBUG */ } - offs = page_offset(rec_get_start(rec, offsets)); + offs = rec_get_start(rec, offsets) - page; i = rec_offs_size(offsets); if (UNIV_UNLIKELY(offs + i >= srv_page_size)) { ib::error() << "Record offset out of bounds: " @@ -2301,18 +2231,18 @@ bool page_validate(const page_t* page, const dict_index_t* index) ret = FALSE; } - if (page_dir_slot_get_rec(slot) != rec) { + if (page_dir_slot_get_rec(page, slot) != rec) { ib::error() << "Dir slot does not" " point to right rec at " << offs; ret = FALSE; } - if (ret) { - page_dir_slot_check(slot); + if (ret && !page_dir_slot_check(page, slot)) { + ret = FALSE; } own_count = 0; - if (!page_rec_is_supremum(rec)) { + if (!page_rec_is_supremum(page, rec)) { slot_no++; slot = page_dir_get_nth_slot(page, slot_no); } @@ -2320,9 +2250,10 @@ bool page_validate(const page_t* page, const dict_index_t* index) next_rec: old_rec = rec; - rec = page_rec_get_next_const(rec); + rec = page_rec_get_next(page, rec); - if (UNIV_UNLIKELY(!rec != page_rec_is_supremum(old_rec))) { + if (UNIV_UNLIKELY(!rec + != page_rec_is_supremum(page, old_rec))) { ib::error() << "supremum is not last record: " << offs; ret = FALSE; } @@ -2335,8 +2266,8 @@ bool page_validate(const page_t* page, const dict_index_t* index) count++; own_count++; - if (page_rec_is_infimum(old_rec) - && page_rec_is_user_rec(rec)) { + if (page_rec_is_infimum(page, old_rec) + && page_rec_is_user_rec(page, rec)) { first_rec = rec; } @@ -2402,7 +2333,7 @@ bool page_validate(const page_t* page, const dict_index_t* index) } count++; - offs = page_offset(rec_get_start(rec, offsets)); + offs = rec_get_start(rec, offsets) - page; i = rec_offs_size(offsets); if (UNIV_UNLIKELY(offs + i >= srv_page_size)) { ib::error() << "Free record offset out of bounds: " @@ -2501,7 +2432,7 @@ const rec_t *page_find_rec_max_not_deleted(const page_t *page) if (!(rec[-REC_NEW_INFO_BITS] & (REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG))) prev_rec= rec; - if (!(rec= page_rec_get_next_low(rec, true))) + if (!(rec= page_rec_get_next_low(page, rec, true))) return page + PAGE_NEW_INFIMUM; } while (rec != page + PAGE_NEW_SUPREMUM); return prev_rec; @@ -2515,7 +2446,7 @@ const rec_t *page_find_rec_max_not_deleted(const page_t *page) if (!(rec[-REC_OLD_INFO_BITS] & (REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG))) prev_rec= rec; - if (!(rec= page_rec_get_next_low(rec, false))) + if (!(rec= page_rec_get_next_low(page, rec, false))) return page + PAGE_OLD_INFIMUM; } while (rec != page + PAGE_OLD_SUPREMUM); return prev_rec; diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index 7c10255c7a0d5..43a6018109c26 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -356,17 +356,34 @@ page_zip_dir_get( /** Write a byte string to a ROW_FORMAT=COMPRESSED page. @param[in] b ROW_FORMAT=COMPRESSED index page -@param[in] offset byte offset from b.zip.data +@param[in] offset offset within b.page.zip.data @param[in] len length of the data to write */ -inline void mtr_t::zmemcpy(const buf_block_t &b, ulint offset, ulint len) +void mtr_t::zmemcpy(const buf_block_t &b, const byte *offset, ulint len) { ut_ad(fil_page_get_type(b.page.zip.data) == FIL_PAGE_INDEX || fil_page_get_type(b.page.zip.data) == FIL_PAGE_RTREE); ut_ad(page_zip_simple_validate(&b.page.zip)); - ut_ad(offset + len <= page_zip_get_size(&b.page.zip)); + ut_ad(len); + set_modified(b); - memcpy_low(b, static_cast(offset), &b.page.zip.data[offset], len); - m_last_offset= static_cast(offset + len); + if (!is_logged()) + return; + + const uint16_t o= uint16_t(offset - b.page.zip.data); + ut_ad(o + len <= page_zip_get_size(&b.page.zip)); + + if (len < mtr_buf_t::MAX_DATA_SIZE - (1 + 3 + 3 + 5 + 5)) + { + byte *end= log_write(b.page.id(), &b.page, len, true, o); + ::memcpy(end, offset, len); + m_log.close(end + len); + } + else + { + m_log.close(log_write(b.page.id(), &b.page, len, false, o)); + m_log.push(offset, static_cast(len)); + } + m_last_offset= uint16_t(o + len); } /** Write a byte string to a ROW_FORMAT=COMPRESSED page. @@ -376,8 +393,8 @@ inline void mtr_t::zmemcpy(const buf_block_t &b, ulint offset, ulint len) @param[in] len length of the data to write @tparam w write request type */ template -inline void mtr_t::zmemcpy(const buf_block_t &b, void *dest, const void *str, - ulint len) +void +mtr_t::zmemcpy(const buf_block_t &b, void *dest, const void *str, ulint len) { byte *d= static_cast(dest); const byte *s= static_cast(str); @@ -399,7 +416,73 @@ inline void mtr_t::zmemcpy(const buf_block_t &b, void *dest, const void *str, len= static_cast(end - d); } ::memcpy(d, s, len); - zmemcpy(b, d - b.page.zip.data, len); + zmemcpy(b, d, len); +} + +/** Log that a string of bytes was copied from the same +ROW_FORMAT=COMPRESSED page. +@param b buffer page +@param d destination offset within the page +@param s source offset within the page +@param len length of the data to copy */ +void mtr_t::zmemmove(const buf_block_t &b, const byte *d, const byte *s, + size_t len) +{ + ut_ad(len); + ut_ad(s != d); + const size_t zip_size= b.page.zip_size(); + ut_d(const byte *frame= b.page.zip.data); + ut_ad(d >= frame + 8); + ut_ad(s >= frame + 8); + ut_ad(s <= frame + zip_size); + ut_ad(d <= frame + zip_size); + ut_ad(s + len <= frame + zip_size); + ut_ad(d + len <= frame + zip_size); + + set_modified(b); + if (!is_logged()) + return; + static_assert(MIN_3BYTE > UNIV_ZIP_SIZE_MAX, "consistency"); + size_t lenlen= (len < MIN_2BYTE ? 1 : 2); + /* The source offset is encoded relative to the destination offset, + with the sign in the least significant bit. */ + uint16_t S= s > d ? uint16_t((s - d) << 1) : uint16_t((d - s) << 1 | 1); + /* The source offset 0 is not possible. */ + S= uint16_t(S - (1U << 1)); + const uint16_t D= uint16_t(ut_align_offset(d, zip_size)); + size_t slen= (S < MIN_2BYTE ? 1 : 2); + byte *l= log_write(b.page.id(), &b.page, lenlen + slen, true, D); + l= mlog_encode_varint(l, len); + l= mlog_encode_varint(l, S); + m_log.close(l); + m_last_offset= uint16_t(D + len); +} + +/** Log an initialization of a string of bytes. +@param b ROW_FORMAT=COMPRESSED buffer page +@param ofs byte offset within the compressed buffer page frame +@param len length of the data to write +@param val the data byte to write */ +void mtr_t::zmemset(const buf_block_t &b, const byte *ofs, size_t len, + byte val) +{ + ut_ad(len); + set_modified(b); + if (!is_logged()) + return; + + const auto zip_size= b.page.zip_size(); + ut_ad(ofs >= b.page.zip.data); + ut_ad(ofs + len <= b.page.zip.data + zip_size); + + static_assert(MIN_3BYTE > UNIV_ZIP_SIZE_MAX, "consistency"); + size_t lenlen= (len < MIN_2BYTE ? 1 + 1 : 2 + 1); + const uint16_t o= uint16_t(ut_align_offset(ofs, zip_size)); + byte *l= log_write(b.page.id(), &b.page, lenlen, true, o); + l= mlog_encode_varint(l, len); + *l++= val; + m_log.close(l); + m_last_offset= uint16_t(o + len); } /** Write redo log for compressing a ROW_FORMAT=COMPRESSED index page. @@ -414,7 +497,7 @@ static void page_zip_compress_write_log(buf_block_t *block, if (!mtr->is_logged()) return; - const page_t *page= block->page.frame; + page_t *page= block->page.frame; const page_zip_des_t *page_zip= &block->page.zip; /* Read the number of user records. */ ulint trailer_size= ulint(page_dir_get_n_heap(page_zip->data)) - @@ -434,10 +517,12 @@ static void page_zip_compress_write_log(buf_block_t *block, ut_a(page_zip->m_end + trailer_size <= page_zip_get_size(page_zip)); mtr->init(block); - mtr->zmemcpy(*block, FIL_PAGE_PREV, page_zip->m_end - FIL_PAGE_PREV); + mtr->zmemcpy(*block, &page_zip->data[FIL_PAGE_PREV], + page_zip->m_end - FIL_PAGE_PREV); if (trailer_size) - mtr->zmemcpy(*block, page_zip_get_size(page_zip) - trailer_size, + mtr->zmemcpy(*block, + &page_zip->data[page_zip_get_size(page_zip) - trailer_size], trailer_size); } @@ -448,13 +533,13 @@ static ulint page_zip_get_n_prev_extern( /*=======================*/ + const page_t* page, /*!< in: B-tree leaf page */ const page_zip_des_t* page_zip,/*!< in: dense page directory on compressed page */ const rec_t* rec, /*!< in: compact physical record on a B-tree leaf page */ const dict_index_t* index) /*!< in: record descriptor */ { - const page_t* page = page_align(rec); ulint n_ext = 0; ulint i; ulint left; @@ -3532,6 +3617,7 @@ page_zip_write_rec_ext( page_zip_des_t* const page_zip = &block->page.zip; ut_ad(rec_offs_validate(rec, index, offsets)); + ut_ad(page == block->page.frame); MEM_CHECK_DEFINED(rec, rec_offs_data_size(offsets)); MEM_CHECK_DEFINED(rec - rec_offs_extra_size(offsets), rec_offs_extra_size(offsets)); @@ -3548,7 +3634,7 @@ page_zip_write_rec_ext( if (n_ext) { ulint blob_no = page_zip_get_n_prev_extern( - page_zip, rec, index); + page, page_zip, rec, index); byte* ext_end = externs - page_zip->n_blobs * FIELD_REF_SIZE; ut_ad(blob_no <= page_zip->n_blobs); externs -= blob_no * FIELD_REF_SIZE; @@ -3561,9 +3647,7 @@ page_zip_write_rec_ext( byte* ext_start = ext_end - n_ext * FIELD_REF_SIZE; memmove(ext_start, ext_end, len); - mtr->memmove(*block, - ext_start - page_zip->data, - ext_end - page_zip->data, len); + mtr->zmemmove(*block, ext_start, ext_end, len); } } @@ -3601,7 +3685,7 @@ page_zip_write_rec_ext( byte* sys = storage - sys_len * (heap_no - 1); memcpy(sys, src, sys_len); i++; /* skip also roll_ptr */ - mtr->zmemcpy(*block, sys - page_zip->data, sys_len); + mtr->zmemcpy(*block, sys, sys_len); } else if (rec_offs_nth_extern(offsets, i)) { src = rec_get_nth_field(rec, offsets, i, &len); @@ -3619,8 +3703,7 @@ page_zip_write_rec_ext( externs -= FIELD_REF_SIZE; ut_ad(data < externs); memcpy(externs, src, FIELD_REF_SIZE); - mtr->zmemcpy(*block, externs - page_zip->data, - FIELD_REF_SIZE); + mtr->zmemcpy(*block, externs, FIELD_REF_SIZE); } } @@ -3646,13 +3729,14 @@ void page_zip_write_rec(buf_block_t *block, const byte *rec, const dict_index_t *index, const rec_offs *offsets, ulint create, mtr_t *mtr) { - const page_t* const page = block->page.frame; + const page_t* const page = page_align(rec); page_zip_des_t* const page_zip = &block->page.zip; byte* data; byte* storage; ulint heap_no; byte* slot; + ut_ad(page == block->page.frame); ut_ad(page_zip_simple_validate(page_zip)); ut_ad(page_zip_get_size(page_zip) > PAGE_DATA + page_zip_dir_size(page_zip)); @@ -3686,7 +3770,7 @@ void page_zip_write_rec(buf_block_t *block, const byte *rec, if (s != *slot) { *slot = s; - mtr->zmemcpy(*block, slot - page_zip->data, 1); + mtr->zmemcpy(*block, slot, 1); } ut_ad(rec_get_start((rec_t*) rec, offsets) >= page + PAGE_ZIP_START); @@ -3766,8 +3850,7 @@ void page_zip_write_rec(buf_block_t *block, const byte *rec, memcpy(sys, src, sys_len); src += sys_len; - mtr->zmemcpy(*block, sys - page_zip->data, - sys_len); + mtr->zmemcpy(*block, sys, sys_len); /* Log the last bytes of the record. */ len = rec_offs_data_size(offsets) - ulint(src - rec); @@ -3810,7 +3893,7 @@ void page_zip_write_rec(buf_block_t *block, const byte *rec, ut_a(!*data); ut_ad((ulint) (data - page_zip->data) < page_zip_get_size(page_zip)); - mtr->zmemcpy(*block, page_zip->m_end, + mtr->zmemcpy(*block, page_zip->data + page_zip->m_end, data - page_zip->data - page_zip->m_end); page_zip->m_end = uint16_t(data - page_zip->data); page_zip->m_nonempty = TRUE; @@ -3864,7 +3947,7 @@ page_zip_write_blob_ptr( MEM_CHECK_DEFINED(rec - rec_offs_extra_size(offsets), rec_offs_extra_size(offsets)); - blob_no = page_zip_get_n_prev_extern(page_zip, rec, index) + blob_no = page_zip_get_n_prev_extern(page, page_zip, rec, index) + rec_get_n_extern_new(rec, index, n); ut_a(blob_no < page_zip->n_blobs); @@ -4000,9 +4083,7 @@ page_zip_write_trx_id_and_roll_ptr( The total size is: x+13 versus x+2+15-len = x+17-len. To save space, we must have len>4. */ memcpy(storage, prev, len); - mtr->memmove(*block, ulint(storage - page_zip->data), - ulint(storage - page_zip->data) + sys_len, - len); + mtr->zmemmove(*block, storage, storage + sys_len, len); storage += len; field += len; if (UNIV_LIKELY(len < sys_len)) { @@ -4063,7 +4144,7 @@ page_zip_clear_rec( MEM_CHECK_DEFINED(rec - rec_offs_extra_size(offsets), rec_offs_extra_size(offsets)); - if (!page_is_leaf(block->page.frame)) { + if (!page_rec_is_leaf(rec)) { /* Clear node_ptr. On the compressed page, there is an array of node_ptr immediately before the dense page directory, at the very end of the page. */ @@ -4080,7 +4161,7 @@ page_zip_clear_rec( len = REC_NODE_PTR_SIZE; clear_page_zip: memset(storage, 0, len); - mtr->memset(*block, storage - page_zip->data, len, 0); + mtr->zmemset(*block, storage, len, 0); } else if (index->is_clust()) { /* Clear trx_id and roll_ptr. On the compressed page, there is an array of these fields immediately before the @@ -4176,8 +4257,9 @@ page_zip_dir_insert( byte* rec, /*!< in: record to insert */ mtr_t* mtr) /*!< in/out: mini-transaction */ { - ut_ad(page_align(cursor->rec) == cursor->block->page.frame); - ut_ad(page_align(rec) == cursor->block->page.frame); + const page_t *const page= cursor->block->page.frame; + ut_ad(page_align(cursor->rec) == page); + ut_ad(page_align(rec) == page); page_zip_des_t *const page_zip= &cursor->block->page.zip; ulint n_dense; @@ -4185,12 +4267,12 @@ page_zip_dir_insert( byte* slot_free; ut_ad(cursor->rec != rec); - ut_ad(page_rec_get_next_const(cursor->rec) == rec); + ut_ad(page_rec_get_next(page, cursor->rec) == rec); ut_ad(page_zip_simple_validate(page_zip)); MEM_CHECK_DEFINED(page_zip->data, page_zip_get_size(page_zip)); - if (page_rec_is_infimum(cursor->rec)) { + if (page_rec_is_infimum(page, cursor->rec)) { /* Use the first slot. */ slot_rec = page_zip->data + page_zip_get_size(page_zip); } else { @@ -4206,7 +4288,7 @@ page_zip_dir_insert( } slot_rec = page_zip_dir_find_low(start, end, - page_offset(cursor->rec)); + cursor->rec - page); ut_a(slot_rec); } @@ -4222,7 +4304,7 @@ page_zip_dir_insert( did not increment n_heap. */ ut_ad(rec_get_heap_no_new(rec) < n_dense + 1 + PAGE_HEAP_NO_USER_LOW); - ut_ad(page_offset(rec) >= free_rec); + ut_ad(rec - page >= free_rec); slot_free = page_zip_dir_find(page_zip, free_rec); ut_ad(slot_free); slot_free += PAGE_ZIP_DIR_SLOT_SIZE; @@ -4241,21 +4323,21 @@ page_zip_dir_insert( /* Shift the dense directory to allocate place for rec. */ memmove_aligned<2>(slot_free - PAGE_ZIP_DIR_SLOT_SIZE, slot_free, slot_len); - mtr->memmove(*cursor->block, (slot_free - page_zip->data) - - PAGE_ZIP_DIR_SLOT_SIZE, - slot_free - page_zip->data, slot_len); + mtr->zmemmove(*cursor->block, + slot_free - PAGE_ZIP_DIR_SLOT_SIZE, + slot_free, slot_len); } /* Write the entry for the inserted record. The "owned" flag must be zero. */ - uint16_t offs = page_offset(rec); + uint16_t offs = uint16_t(rec - page); if (rec_get_deleted_flag(rec, true)) { offs |= PAGE_ZIP_DIR_SLOT_DEL; } mach_write_to_2(slot_rec - PAGE_ZIP_DIR_SLOT_SIZE, offs); - mtr->zmemcpy(*cursor->block, slot_rec - page_zip->data - - PAGE_ZIP_DIR_SLOT_SIZE, PAGE_ZIP_DIR_SLOT_SIZE); + mtr->zmemcpy(*cursor->block, slot_rec - PAGE_ZIP_DIR_SLOT_SIZE, + PAGE_ZIP_DIR_SLOT_SIZE); } /** Shift the dense page directory and the array of BLOB pointers @@ -4270,9 +4352,10 @@ void page_zip_dir_delete(buf_block_t *block, byte *rec, const dict_index_t *index, const rec_offs *offsets, const byte *free, mtr_t *mtr) { - ut_ad(page_align(rec) == block->page.frame); + page_t *const page= page_align(rec); page_zip_des_t *const page_zip= &block->page.zip; + ut_ad(page == block->page.frame); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_comp(offsets)); @@ -4283,23 +4366,20 @@ void page_zip_dir_delete(buf_block_t *block, byte *rec, mach_write_to_2(rec - REC_NEXT, free ? static_cast(free - rec) : 0); - byte *page_free= my_assume_aligned<2>(PAGE_FREE + PAGE_HEADER + - block->page.frame); + byte *page_free= my_assume_aligned<2>(PAGE_FREE + PAGE_HEADER + page); mtr->write<2>(*block, page_free, page_offset(rec)); - byte *garbage= my_assume_aligned<2>(PAGE_GARBAGE + PAGE_HEADER + - block->page.frame); + byte *garbage= my_assume_aligned<2>(PAGE_GARBAGE + PAGE_HEADER + page); mtr->write<2>(*block, garbage, rec_offs_size(offsets) + mach_read_from_2(garbage)); compile_time_assert(PAGE_GARBAGE == PAGE_FREE + 2); memcpy_aligned<4>(PAGE_FREE + PAGE_HEADER + page_zip->data, page_free, 4); byte *slot_rec= page_zip_dir_find(page_zip, page_offset(rec)); ut_a(slot_rec); - uint16_t n_recs= page_get_n_recs(block->page.frame); + uint16_t n_recs= page_get_n_recs(page); ut_ad(n_recs); - ut_ad(n_recs > 1 || page_get_page_no(block->page.frame) == index->page); + ut_ad(n_recs > 1 || page_get_page_no(page) == index->page); /* This could not be done before page_zip_dir_find(). */ - byte *page_n_recs= my_assume_aligned<2>(PAGE_N_RECS + PAGE_HEADER + - block->page.frame); + byte *page_n_recs= my_assume_aligned<2>(PAGE_N_RECS + PAGE_HEADER + page); mtr->write<2>(*block, page_n_recs, n_recs - 1U); memcpy_aligned<2>(PAGE_N_RECS + PAGE_HEADER + page_zip->data, page_n_recs, 2); @@ -4324,26 +4404,26 @@ void page_zip_dir_delete(buf_block_t *block, byte *rec, { memmove_aligned<2>(slot_free + PAGE_ZIP_DIR_SLOT_SIZE, slot_free, slot_len); - mtr->memmove(*block, (slot_free - page_zip->data) + PAGE_ZIP_DIR_SLOT_SIZE, - slot_free - page_zip->data, slot_len); + mtr->zmemmove(*block, slot_free + PAGE_ZIP_DIR_SLOT_SIZE, + slot_free, slot_len); } /* Write the entry for the deleted record. The "owned" and "deleted" flags will be cleared. */ mach_write_to_2(slot_free, page_offset(rec)); - mtr->zmemcpy(*block, slot_free - page_zip->data, 2); + mtr->zmemcpy(*block, slot_free, 2); if (const ulint n_ext= rec_offs_n_extern(offsets)) { ut_ad(index->is_primary()); - ut_ad(page_is_leaf(block->page.frame)); + ut_ad(page_is_leaf(page)); /* Shift and zero fill the array of BLOB pointers. */ - ulint blob_no = page_zip_get_n_prev_extern(page_zip, rec, index); + ulint blob_no = page_zip_get_n_prev_extern(page, page_zip, rec, index); ut_a(blob_no + n_ext <= page_zip->n_blobs); byte *externs= page_zip->data + page_zip_get_size(page_zip) - - (page_dir_get_n_heap(block->page.frame) - PAGE_HEAP_NO_USER_LOW) * + (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW) * PAGE_ZIP_CLUST_LEAF_SLOT_SIZE; byte *ext_end= externs - page_zip->n_blobs * FIELD_REF_SIZE; @@ -4352,11 +4432,11 @@ void page_zip_dir_delete(buf_block_t *block, byte *rec, BTR_EXTERN_FIELD_REF_SIZE) { memmove(ext_end + n_ext * FIELD_REF_SIZE, ext_end, ext_len); - mtr->memmove(*block, (ext_end - page_zip->data) + n_ext * FIELD_REF_SIZE, - ext_end - page_zip->data, ext_len); + mtr->zmemmove(*block, ext_end + n_ext * FIELD_REF_SIZE, ext_end, + ext_len); } memset(ext_end, 0, n_ext * FIELD_REF_SIZE); - mtr->memset(*block, ext_end - page_zip->data, n_ext * FIELD_REF_SIZE, 0); + mtr->zmemset(*block, ext_end, n_ext * FIELD_REF_SIZE, 0); page_zip->n_blobs = (page_zip->n_blobs - n_ext) & ((1U << 12) - 1); } @@ -4389,7 +4469,7 @@ page_zip_reorganize( mtr_t* mtr, /*!< in: mini-transaction */ bool restore)/*!< whether to restore on failure */ { - page_t* page = buf_block_get_frame(block); + page_t* page = block->page.frame; buf_block_t* temp_block; page_t* temp_page; @@ -4411,8 +4491,7 @@ page_zip_reorganize( temp_page = temp_block->page.frame; /* Copy the old page to temporary space */ - memcpy_aligned(temp_page, block->page.frame, - srv_page_size); + memcpy_aligned(temp_page, page, srv_page_size); /* Recreate the page: note that global data on page (possible segment headers, next page-field, etc.) is preserved intact */ diff --git a/storage/innobase/rem/rem0cmp.cc b/storage/innobase/rem/rem0cmp.cc index 536ea224d1815..e5c26937a8419 100644 --- a/storage/innobase/rem/rem0cmp.cc +++ b/storage/innobase/rem/rem0cmp.cc @@ -490,7 +490,7 @@ cmp_dtuple_rec_with_match_bytes( if (UNIV_UNLIKELY(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(rec, rec_offs_comp(offsets)))) { - ut_ad(page_rec_is_first(rec, page_align(rec))); + ut_ad(page_rec_is_first(page_align(rec), rec)); ut_ad(!page_has_prev(page_align(rec))); ut_ad(rec_is_metadata(rec, *index)); return 1; diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 47be5e447f546..e3c46eb563d0b 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -2173,6 +2173,7 @@ rec_validate_old( /***************************************************************//** Validates the consistency of a physical record. @return TRUE if ok */ +ATTRIBUTE_COLD ibool rec_validate( /*=========*/ @@ -2230,6 +2231,7 @@ rec_validate( /***************************************************************//** Prints an old-style physical record. */ +ATTRIBUTE_COLD void rec_print_old( /*==========*/ @@ -2280,6 +2282,7 @@ rec_print_old( /***************************************************************//** Prints a physical record in ROW_FORMAT=COMPACT. Ignores the record header. */ +ATTRIBUTE_COLD static void rec_print_comp( @@ -2332,6 +2335,7 @@ rec_print_comp( /***************************************************************//** Prints an old-style spatial index record. */ +ATTRIBUTE_COLD static void rec_print_mbr_old( @@ -2407,6 +2411,7 @@ rec_print_mbr_old( /***************************************************************//** Prints a spatial index record. */ +ATTRIBUTE_COLD void rec_print_mbr_rec( /*==============*/ @@ -2475,6 +2480,7 @@ rec_print_mbr_rec( /***************************************************************//** Prints a physical record. */ +ATTRIBUTE_COLD void rec_print_new( /*==========*/ @@ -2508,6 +2514,7 @@ rec_print_new( /***************************************************************//** Prints a physical record. */ +ATTRIBUTE_COLD void rec_print( /*======*/ @@ -2539,6 +2546,7 @@ rec_print( @param[in] rec physical record @param[in] info rec_get_info_bits(rec) @param[in] offsets rec_get_offsets(rec) */ +ATTRIBUTE_COLD void rec_print( std::ostream& o, @@ -2597,6 +2605,7 @@ rec_print( @param[in,out] o output stream @param[in] r record to display @return the output stream */ +ATTRIBUTE_COLD std::ostream& operator<<(std::ostream& o, const rec_index_print& r) { @@ -2616,6 +2625,7 @@ operator<<(std::ostream& o, const rec_index_print& r) @param[in,out] o output stream @param[in] r record to display @return the output stream */ +ATTRIBUTE_COLD std::ostream& operator<<(std::ostream& o, const rec_offsets_print& r) { diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 0eda905deccca..846b07a44a5d1 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -348,33 +348,32 @@ class RecIterator { bool remove(rec_offs* offsets) UNIV_NOTHROW { const dict_index_t* const index = m_cur.index; - ut_ad(page_is_leaf(m_cur.block->page.frame)); + page_t* const page = page_cur_get_page(&m_cur); + ut_ad(page_is_leaf(page)); /* We can't end up with an empty page unless it is root. */ - if (page_get_n_recs(m_cur.block->page.frame) <= 1) { + if (page_get_n_recs(page) <= 1) { return(false); } if (!rec_offs_any_extern(offsets) && m_cur.block->page.id().page_no() != index->page - && ((page_get_data_size(m_cur.block->page.frame) + && ((page_get_data_size(page) - rec_offs_size(offsets) < BTR_CUR_PAGE_COMPRESS_LIMIT(index)) - || !page_has_siblings(m_cur.block->page.frame) - || (page_get_n_recs(m_cur.block->page.frame) < 2))) { + || !page_has_siblings(page) + || (page_get_n_recs(page) < 2))) { return false; } #ifdef UNIV_ZIP_DEBUG page_zip_des_t* page_zip = buf_block_get_page_zip(m_cur.block); - ut_a(!page_zip || page_zip_validate( - page_zip, m_cur.block->page.frame, index)); + ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ page_cur_delete_rec(&m_cur, offsets, &m_mtr); #ifdef UNIV_ZIP_DEBUG - ut_a(!page_zip || page_zip_validate( - page_zip, m_cur.block->page.frame, index)); + ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ return true; @@ -1596,7 +1595,8 @@ inline bool IndexPurge::open() noexcept if (m_pcur.open_leaf(true, m_index, BTR_MODIFY_LEAF, &m_mtr) != DB_SUCCESS) return false; - rec_t *rec= page_rec_get_next(btr_pcur_get_rec(&m_pcur)); + rec_t *rec= page_rec_get_next(btr_pcur_get_page(&m_pcur), + btr_pcur_get_rec(&m_pcur)); if (!rec) return false; if (rec_is_metadata(rec, *m_index)) @@ -1863,7 +1863,6 @@ dberr_t PageConverter::update_records( buf_block_t* block) UNIV_NOTHROW { - ibool comp = dict_table_is_comp(m_cfg->m_table); bool clust_index = m_index->m_srv_index == m_cluster_index; /* This will also position the cursor on the first user record. */ @@ -1873,12 +1872,14 @@ PageConverter::update_records( return DB_CORRUPTION; } + page_t* page = block->page.frame; + const auto comp = page_is_comp(page); ulint deleted; - if (!page_has_prev(block->page.frame) + if (!page_has_prev(page) && m_index->m_srv_index->is_instant()) { /* Expect to find the hidden metadata record */ - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { return DB_CORRUPTION; } @@ -2010,7 +2011,7 @@ PageConverter::update_index_page( m_index->m_srv_index->id); if (UNIV_LIKELY_NULL(block->page.zip.data)) { memcpy(&block->page.zip.data[PAGE_HEADER + PAGE_INDEX_ID], - &block->page.frame[PAGE_HEADER + PAGE_INDEX_ID], 8); + &page[PAGE_HEADER + PAGE_INDEX_ID], 8); } if (m_index->m_srv_index->is_clust()) { @@ -2019,12 +2020,12 @@ PageConverter::update_index_page( } } else if (page_is_leaf(page)) { /* Set PAGE_MAX_TRX_ID on secondary index leaf pages. */ - mach_write_to_8(&block->page.frame - [PAGE_HEADER + PAGE_MAX_TRX_ID], m_trx->id); + mach_write_to_8(&page[PAGE_HEADER + PAGE_MAX_TRX_ID], + m_trx->id); if (UNIV_LIKELY_NULL(block->page.zip.data)) { memcpy_aligned<8>(&block->page.zip.data [PAGE_HEADER + PAGE_MAX_TRX_ID], - &block->page.frame + &page [PAGE_HEADER + PAGE_MAX_TRX_ID], 8); } } else { @@ -2034,9 +2035,7 @@ PageConverter::update_index_page( in MySQL 5.6, 5.7 and MariaDB 10.0 and 10.1 would set the field to the transaction ID even on clustered index pages. */ - memset_aligned<8>(&block->page.frame - [PAGE_HEADER + PAGE_MAX_TRX_ID], - 0, 8); + memset_aligned<8>(&page[PAGE_HEADER + PAGE_MAX_TRX_ID], 0, 8); if (UNIV_LIKELY_NULL(block->page.zip.data)) { memset_aligned<8>(&block->page.zip.data [PAGE_HEADER + PAGE_MAX_TRX_ID], @@ -2057,7 +2056,7 @@ PageConverter::update_index_page( return(DB_SUCCESS); } - return page_is_leaf(block->page.frame) + return page_is_leaf(page) ? update_records(block) : DB_SUCCESS; } @@ -2095,10 +2094,11 @@ PageConverter::update_page(buf_block_t* block, uint16_t& page_type) UNIV_NOTHROW { dberr_t err = DB_SUCCESS; + byte* frame = get_frame(block); ut_ad(!block->page.zip.data == !is_compressed_table()); - switch (page_type = fil_page_get_type(get_frame(block))) { + switch (page_type = fil_page_get_type(frame)) { case FIL_PAGE_TYPE_FSP_HDR: ut_a(block->page.id().page_no() == 0); /* Work directly on the uncompressed page headers. */ @@ -2116,9 +2116,8 @@ PageConverter::update_page(buf_block_t* block, uint16_t& page_type) /* fall through */ case FIL_PAGE_TYPE_INSTANT: /* This is on every page in the tablespace. */ - mach_write_to_4( - get_frame(block) - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, get_space_id()); + mach_write_to_4(frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, + get_space_id()); /* Only update the Btree nodes. */ return(update_index_page(block)); @@ -2128,8 +2127,7 @@ PageConverter::update_page(buf_block_t* block, uint16_t& page_type) return(DB_CORRUPTION); case FIL_PAGE_TYPE_XDES: - err = set_current_xdes( - block->page.id().page_no(), get_frame(block)); + err = set_current_xdes(block->page.id().page_no(), frame); /* fall through */ case FIL_PAGE_INODE: case FIL_PAGE_TYPE_TRX_SYS: @@ -2142,9 +2140,8 @@ PageConverter::update_page(buf_block_t* block, uint16_t& page_type) /* Work directly on the uncompressed page headers. */ /* This is on every page in the tablespace. */ - mach_write_to_4( - get_frame(block) - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, get_space_id()); + mach_write_to_4(frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, + get_space_id()); return(err); } @@ -2178,8 +2175,7 @@ dberr_t PageConverter::operator()(buf_block_t* block) UNIV_NOTHROW memset_aligned<8>(frame + FIL_PAGE_LSN, 0, 8); if (!block->page.zip.data) { - buf_flush_init_for_writing( - NULL, block->page.frame, NULL, full_crc32); + buf_flush_init_for_writing(NULL, frame, NULL, full_crc32); } else if (fil_page_type_is_index(page_type)) { buf_flush_init_for_writing( NULL, block->page.zip.data, &block->page.zip, @@ -2452,7 +2448,7 @@ row_import_set_sys_max_row_id( if (!rec) { /* The table is corrupted. */ - } else if (page_rec_is_infimum(rec)) { + } else if (btr_pcur_is_before_first_on_page(&pcur)) { /* The table is empty. */ } else if (rec_is_metadata(rec, *index)) { /* The clustered index contains the metadata @@ -3455,7 +3451,7 @@ static dberr_t handle_instant_metadata(dict_table_t *table, while (btr_page_get_level(page.get()) != 0) { - const rec_t *rec= page_rec_get_next(page_get_infimum_rec(page.get())); + const rec_t *rec= page_rec_get_first(page.get()); if (!rec) return DB_CORRUPTION; @@ -3480,10 +3476,10 @@ static dberr_t handle_instant_metadata(dict_table_t *table, return err; } - const auto *rec= page_rec_get_next_const(page_get_infimum_rec(page.get())); - const auto comp= dict_table_is_comp(index->table); + const auto *rec= page_rec_get_first(page.get()); + const auto comp= page_is_comp(page.get()); - if (!rec || page_rec_is_supremum(rec)) + if (!rec || page_rec_is_supremum(page.get(), rec)) { corrupted_metadata: ib::error() << "Table " << index->table->name diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 0f3f7dd3166ce..b219c88eadd6d 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -838,11 +838,15 @@ row_ins_foreign_report_add_err( fprintf(ef, ", in index %s,\n" "the closest match we can find is record:\n", foreign->referenced_index->name()); - if (rec && page_rec_is_supremum(rec)) { + if (rec) { + const page_t* page = page_align(rec); + /* If the cursor ended on a supremum record, it is better to report the previous record in the error message, so that the user gets a more descriptive error message. */ - rec = page_rec_get_prev_const(rec); + if (page_rec_is_supremum(page, rec)) { + rec = page_rec_get_prev(page, rec); + } } if (rec) { @@ -1149,7 +1153,7 @@ row_ins_foreign_check_on_constraint( clust_rec = btr_pcur_get_rec(cascade->pcur); clust_block = btr_pcur_get_block(cascade->pcur); - if (!page_rec_is_user_rec(clust_rec) + if (!page_rec_is_user_rec(clust_block->page.frame, clust_rec) || btr_pcur_get_low_match(cascade->pcur) < dict_index_get_n_unique(clust_index)) { @@ -1635,7 +1639,7 @@ row_ins_check_foreign_constraint( const rec_t* rec = btr_pcur_get_rec(&pcur); const buf_block_t* block = btr_pcur_get_block(&pcur); - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(block->page.frame, rec)) { continue; } @@ -1644,7 +1648,7 @@ row_ins_check_foreign_constraint( check_index->n_core_fields, ULINT_UNDEFINED, &heap); - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(block->page.frame, rec)) { if (skip_gap_lock) { @@ -2121,11 +2125,12 @@ row_ins_scan_sec_index_for_duplicate( /* Scan index records and check if there is a duplicate */ do { - const rec_t* rec = btr_pcur_get_rec(&pcur); + const rec_t* const rec = btr_pcur_get_rec(&pcur); const buf_block_t* block = btr_pcur_get_block(&pcur); const ulint lock_type = LOCK_ORDINARY; + const page_t* const page = block->page.frame; - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(page, rec)) { continue; } @@ -2161,7 +2166,7 @@ row_ins_scan_sec_index_for_duplicate( goto end_scan; } - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { continue; } @@ -2273,10 +2278,11 @@ row_ins_duplicate_error_in_clust_online( { dberr_t err = DB_SUCCESS; const rec_t* rec = btr_cur_get_rec(cursor); + const page_t* page = btr_cur_get_page(cursor); ut_ad(!cursor->index()->is_instant()); - if (cursor->low_match >= n_uniq && !page_rec_is_infimum(rec)) { + if (cursor->low_match >= n_uniq && !page_rec_is_infimum(page, rec)) { *offsets = rec_get_offsets(rec, cursor->index(), *offsets, cursor->index()->n_fields, ULINT_UNDEFINED, heap); @@ -2286,11 +2292,13 @@ row_ins_duplicate_error_in_clust_online( } } - if (!(rec = page_rec_get_next_const(btr_cur_get_rec(cursor)))) { + rec = page_rec_get_next(page, rec); + + if (!rec) { return DB_CORRUPTION; } - if (cursor->up_match >= n_uniq && !page_rec_is_supremum(rec)) { + if (cursor->up_match >= n_uniq && !page_rec_is_supremum(page, rec)) { *offsets = rec_get_offsets(rec, cursor->index(), *offsets, cursor->index()->n_fields, ULINT_UNDEFINED, heap); @@ -2317,7 +2325,6 @@ row_ins_duplicate_error_in_clust( que_thr_t* thr) /*!< in: query thread */ { dberr_t err; - rec_t* rec; ulint n_unique; trx_t* trx = thr_get_trx(thr); mem_heap_t*heap = NULL; @@ -2341,12 +2348,11 @@ row_ins_duplicate_error_in_clust( that a duplicate key violation may occur, this may not be the case. */ n_unique = dict_index_get_n_unique(cursor->index()); + const page_t *const page = btr_cur_get_page(cursor); + const rec_t* rec = btr_cur_get_rec(cursor); if (cursor->low_match >= n_unique) { - - rec = btr_cur_get_rec(cursor); - - if (!page_rec_is_infimum(rec)) { + if (!page_rec_is_infimum(page, rec)) { offsets = rec_get_offsets(rec, cursor->index(), offsets, cursor->index() @@ -2400,7 +2406,7 @@ row_ins_duplicate_error_in_clust( && entry->vers_history_row()) { ulint trx_id_len; - byte *trx_id = rec_get_nth_field( + const byte *trx_id = rec_get_nth_field( rec, offsets, n_unique, &trx_id_len); ut_ad(trx_id_len == DATA_TRX_ID_LEN); @@ -2416,10 +2422,9 @@ row_ins_duplicate_error_in_clust( err = DB_SUCCESS; if (cursor->up_match >= n_unique) { + rec = page_rec_get_next(page, rec); - rec = page_rec_get_next(btr_cur_get_rec(cursor)); - - if (rec && !page_rec_is_supremum(rec)) { + if (rec && !page_rec_is_supremum(page, rec)) { offsets = rec_get_offsets(rec, cursor->index(), offsets, cursor->index() @@ -2496,7 +2501,7 @@ row_ins_must_modify_rec( return(cursor->low_match >= dict_index_get_n_unique_in_tree(cursor->index()) - && !page_rec_is_infimum(btr_cur_get_rec(cursor))); + && !page_cur_is_before_first(&cursor->page_cur)); } /** Insert the externally stored fields (off-page columns) @@ -2687,10 +2692,9 @@ row_ins_clust_index_entry_low( #ifdef UNIV_DEBUG { page_t* page = btr_pcur_get_page(&pcur); - rec_t* first_rec = page_rec_get_next( - page_get_infimum_rec(page)); + rec_t* first_rec = page_rec_get_first(page); - ut_ad(page_rec_is_supremum(first_rec) + ut_ad(page_rec_is_supremum(page, first_rec) || rec_n_fields_is_sane(index, first_rec, entry)); } #endif /* UNIV_DEBUG */ @@ -2700,7 +2704,7 @@ row_ins_clust_index_entry_low( DBUG_EXECUTE_IF("row_ins_row_level", goto skip_bulk_insert;); if (!(flags & BTR_NO_UNDO_LOG_FLAG) - && page_is_empty(block->page.frame) + && page_is_empty(btr_pcur_get_page(&pcur)) && !entry->is_metadata() && !trx->duplicates && !trx->check_unique_secondary && !trx->check_foreigns && !trx->dict_operation @@ -2759,7 +2763,8 @@ row_ins_clust_index_entry_low( if (UNIV_UNLIKELY(entry->info_bits != 0)) { const rec_t* rec = btr_pcur_get_rec(&pcur); - if (rec_get_info_bits(rec, page_rec_is_comp(rec)) + if (rec_get_info_bits(rec, + page_is_comp(btr_pcur_get_page(&pcur))) & REC_INFO_MIN_REC_FLAG) { trx->error_info = index; err = DB_DUPLICATE_KEY; @@ -3029,10 +3034,9 @@ row_ins_sec_index_entry_low( #ifdef UNIV_DEBUG { page_t* page = btr_cur_get_page(&cursor); - rec_t* first_rec = page_rec_get_next( - page_get_infimum_rec(page)); + rec_t* first_rec = page_rec_get_first(page); - ut_ad(page_rec_is_supremum(first_rec) + ut_ad(page_rec_is_supremum(page, first_rec) || rec_n_fields_is_sane(index, first_rec, entry)); } #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index e1ce8161a027c..5a04e4d4c8a78 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -1718,7 +1718,7 @@ row_log_table_apply_delete_low( flag_ok: #endif /* UNIV_DEBUG */ - if (page_rec_is_infimum(btr_pcur_get_rec(pcur)) + if (btr_pcur_is_before_first_on_page(pcur) || btr_pcur_get_low_match(pcur) < index->n_uniq) { /* All secondary index entries should be found, because new_table is being modified by @@ -1802,7 +1802,7 @@ row_log_table_apply_delete( flag_ok: #endif /* UNIV_DEBUG */ - if (page_rec_is_infimum(btr_pcur_get_rec(&pcur)) + if (btr_pcur_is_before_first_on_page(&pcur) || btr_pcur_get_low_match(&pcur) < index->n_uniq) { all_done: mtr_commit(&mtr); @@ -1948,8 +1948,8 @@ row_log_table_apply_update( } #endif /* UNIV_DEBUG */ - ut_ad(!page_rec_is_infimum(btr_pcur_get_rec(&pcur)) - && btr_pcur_get_low_match(&pcur) >= index->n_uniq); + ut_ad(!btr_pcur_is_before_first_on_page(&pcur)); + ut_ad(btr_pcur_get_low_match(&pcur) >= index->n_uniq); /* Prepare to update (or delete) the record. */ rec_offs* cur_offsets = rec_get_offsets( @@ -3098,15 +3098,16 @@ row_log_apply_op_low( /* This test is somewhat similar to row_ins_must_modify_rec(), but not identical for unique secondary indexes. */ if (cursor.low_match >= dict_index_get_n_unique(index) - && !page_rec_is_infimum(btr_cur_get_rec(&cursor))) { + && !page_rec_is_infimum(btr_cur_get_page(&cursor), + btr_cur_get_rec(&cursor))) { /* We have a matching record. */ bool exists = (cursor.low_match == dict_index_get_n_fields(index)); -#ifdef UNIV_DEBUG - rec_t* rec = btr_cur_get_rec(&cursor); - ut_ad(page_rec_is_user_rec(rec)); - ut_ad(!rec_get_deleted_flag(rec, page_rec_is_comp(rec))); -#endif /* UNIV_DEBUG */ + ut_ad(!page_cur_is_before_first(&cursor.page_cur)); + ut_ad(!page_cur_is_after_last(&cursor.page_cur)); + ut_ad(!rec_get_deleted_flag( + btr_cur_get_rec(&cursor), + page_is_comp(btr_cur_get_page(&cursor)))); ut_ad(exists || dict_index_is_unique(index)); @@ -3150,8 +3151,10 @@ row_log_apply_op_low( Thus, the record should still exist. */ ut_ad(cursor.low_match >= dict_index_get_n_fields(index)); - ut_ad(page_rec_is_user_rec( - btr_cur_get_rec(&cursor))); + ut_ad(!page_cur_is_before_first( + &cursor.page_cur)); + ut_ad(!page_cur_is_after_last( + &cursor.page_cur)); } /* As there are no externally stored fields in diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 276bcb6166d13..7ea2dce9bc6c0 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1821,18 +1821,19 @@ row_merge_read_clustered_index( trx->error_key_num = 0; goto func_exit; } else { - rec_t* rec = page_rec_get_next(btr_pcur_get_rec(&pcur)); + page_t* page = btr_pcur_get_page(&pcur); + rec_t* rec = page_rec_get_next(page, btr_pcur_get_rec(&pcur)); if (!rec) { corrupted_metadata: err = DB_CORRUPTION; goto err_exit; } - if (rec_get_info_bits(rec, page_rec_is_comp(rec)) + if (rec_get_info_bits(rec, page_is_comp(page)) & REC_INFO_MIN_REC_FLAG) { if (!clust_index->is_instant()) { goto corrupted_metadata; } - if (page_rec_is_comp(rec) + if (page_is_comp(page) && rec_get_status(rec) != REC_STATUS_INSTANT) { goto corrupted_metadata; } diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 4533b7166b754..3017e7885f0dd 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -696,13 +696,17 @@ static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr) byte* ptr = rec_get_nth_field( rec, offsets, trx_id_pos, &len); ut_ad(len == DATA_TRX_ID_LEN); - size_t offs = page_offset(ptr); - mtr->memset(block, offs, DATA_TRX_ID_LEN, 0); - offs += DATA_TRX_ID_LEN; - mtr->write<1,mtr_t::MAYBE_NOP>( - *block, block->page.frame + offs, - 0x80U); - mtr->memset(block, offs + 1, + size_t offs = size_t(ptr - block->page.frame); + memset(ptr, 0, DATA_TRX_ID_LEN); + mtr->memset(*block, offs, DATA_TRX_ID_LEN, 0); + ptr += DATA_TRX_ID_LEN; + if (*ptr != 0x80) { + *ptr = 0x80; + mtr->memcpy(*block, ptr, 1); + } + memset(ptr + 1, 0, DATA_ROLL_PTR_LEN - 1); + mtr->memset(*block, + offs + DATA_TRX_ID_LEN + 1, DATA_ROLL_PTR_LEN - 1, 0); } } diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc index 4a00b2a430e33..269c53fbe97d2 100644 --- a/storage/innobase/row/row0row.cc +++ b/storage/innobase/row/row0row.cc @@ -1222,7 +1222,8 @@ row_search_on_row_ref( } } - return !page_rec_is_infimum(btr_pcur_get_rec(pcur)) + return !page_rec_is_infimum(btr_pcur_get_page(pcur), + btr_pcur_get_rec(pcur)) && btr_pcur_get_low_match(pcur) == dtuple_get_n_fields(ref); } @@ -1304,11 +1305,8 @@ row_search_index_entry( n_fields = dtuple_get_n_fields(entry); - if (page_rec_is_infimum(rec)) { - - return(ROW_NOT_FOUND); - } else if (low_match != n_fields) { - + if (low_match != n_fields + || page_rec_is_infimum(btr_pcur_get_page(pcur), rec)) { return(ROW_NOT_FOUND); } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 5ebcab88b01c8..233d8c63b8a99 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -817,7 +817,7 @@ row_sel_build_prev_vers( /*====================*/ ReadView* read_view, /*!< in: read view */ dict_index_t* index, /*!< in: plan node for table */ - rec_t* rec, /*!< in: record in a clustered index */ + const rec_t* rec, /*!< in: record in a clustered index */ rec_offs** offsets, /*!< in/out: offsets returned by rec_get_offsets(rec, plan->index) */ mem_heap_t** offset_heap, /*!< in/out: memory heap from which @@ -960,7 +960,7 @@ static dberr_t row_sel_clust_sees(const rec_t *rec, const dict_index_t &index, const ReadView &view) { ut_ad(index.is_primary()); - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page_align(rec), rec)); ut_ad(rec_offs_validate(rec, &index, offsets)); ut_ad(!rec_is_metadata(rec, index)); ut_ad(!index.table->is_temporary()); @@ -987,9 +987,9 @@ row_sel_get_clust_rec( /*==================*/ sel_node_t* node, /*!< in: select_node */ plan_t* plan, /*!< in: plan node for table */ - rec_t* rec, /*!< in: record in a non-clustered index */ + const rec_t* rec, /*!< in: record in a non-clustered index */ que_thr_t* thr, /*!< in: query thread */ - rec_t** out_rec,/*!< out: clustered record or an old version of + const rec_t** out_rec,/*!< out: clustered record or an old version of it, NULL if the old version did not exist in the read view, i.e., it was a fresh inserted version */ @@ -1028,7 +1028,8 @@ row_sel_get_clust_rec( /* Note: only if the search ends up on a non-infimum record is the low_match value the real match to the search tuple */ - if (!page_rec_is_user_rec(clust_rec) + if (!page_rec_is_user_rec(btr_pcur_get_page(&plan->clust_pcur), + clust_rec) || btr_pcur_get_low_match(&(plan->clust_pcur)) < dict_index_get_n_unique(index)) { @@ -1181,15 +1182,16 @@ sel_set_rtr_rec_lock( rtr_rec_vector* match_rec; rtr_rec_vector::iterator end; - rec_offs_init(offsets_); + ut_ad(page_align(first_rec) == cur_block->page.frame); - if (match->locked || page_rec_is_supremum(first_rec)) { + if (match->locked + || page_rec_is_supremum(cur_block->page.frame, first_rec)) { return(DB_SUCCESS_LOCKED_REC); } - ut_ad(page_align(first_rec) == cur_block->page.frame); ut_ad(match->valid); + rec_offs_init(offsets_); match->block->page.lock.x_lock(); retry: cur_block = btr_pcur_get_block(pcur); @@ -1254,7 +1256,7 @@ sel_set_rtr_rec_lock( &pcur->btr_cur.page_cur, pcur->btr_cur.rtr_info); - if (!page_is_leaf(buf_block_get_frame(cur_block))) { + if (!page_is_leaf(cur_block->page.frame)) { /* Page got splitted and promoted (only for root page it is possible). Release the page and ask for a re-search */ @@ -1264,20 +1266,19 @@ sel_set_rtr_rec_lock( goto func_end; } - rec = btr_pcur_get_rec(pcur); - my_offsets = offsets_; - my_offsets = rec_get_offsets(rec, index, my_offsets, - index->n_fields, - ULINT_UNDEFINED, &heap); - /* No match record */ - if (page_rec_is_supremum(rec) || !match->valid) { + if (!match->valid || btr_pcur_is_after_last_on_page(pcur)) { mtr->commit(); mtr->start(); err = DB_RECORD_NOT_FOUND; goto func_end; } + rec = btr_pcur_get_rec(pcur); + my_offsets = offsets_; + my_offsets = rec_get_offsets(rec, index, my_offsets, + index->n_fields, + ULINT_UNDEFINED, &heap); goto retry; } @@ -1580,8 +1581,9 @@ row_sel_try_search_shortcut( } const rec_t* rec = btr_pcur_get_rec(&(plan->pcur)); + const page_t* const page = btr_pcur_get_page(&plan->pcur); - if (!page_rec_is_user_rec(rec) || rec_is_metadata(rec, *index)) { + if (!page_rec_is_user_rec(page, rec) || rec_is_metadata(rec, *index)) { return SEL_RETRY; } @@ -1618,7 +1620,7 @@ row_sel_try_search_shortcut( return SEL_RETRY; } } else if (!srv_read_only_mode) { - trx_id_t trx_id = page_get_max_trx_id(page_align(rec)); + trx_id_t trx_id = page_get_max_trx_id(page); ut_ad(trx_id); if (!node->read_view->sees(trx_id)) { return SEL_RETRY; @@ -1667,10 +1669,10 @@ row_sel( dict_index_t* index; plan_t* plan; mtr_t mtr; - ibool moved; - rec_t* rec; + const page_t* page; + const rec_t* rec; rec_t* old_vers; - rec_t* clust_rec; + const rec_t* clust_rec; /* The following flag becomes TRUE when we are doing a consistent read from a non-clustered index and we must look @@ -1806,11 +1808,12 @@ row_sel( ut_ad(mtr_has_extra_clust_latch == FALSE); rec = btr_pcur_get_rec(&(plan->pcur)); + page = btr_pcur_get_page(&plan->pcur); /* PHASE 1: Set a lock if specified */ if (!node->asc && cursor_just_opened - && !page_rec_is_supremum(rec)) { + && !page_rec_is_supremum(page, rec)) { /* Do not support "descending search" for Spatial index */ ut_ad(!dict_index_is_spatial(index)); @@ -1822,23 +1825,19 @@ row_sel( search result set, resulting in the phantom problem. */ if (!node->read_view) { - const rec_t* next_rec = page_rec_get_next_const(rec); + const rec_t* next_rec = page_rec_get_next(page, rec); if (UNIV_UNLIKELY(!next_rec)) { err = DB_CORRUPTION; goto lock_wait_or_error; } unsigned lock_type; - offsets = rec_get_offsets(next_rec, index, offsets, - index->n_core_fields, - ULINT_UNDEFINED, &heap); - /* At READ UNCOMMITTED or READ COMMITTED isolation level, we lock only the record, i.e., next-key locking is not used. */ if (trx->isolation_level <= TRX_ISO_READ_COMMITTED) { - if (page_rec_is_supremum(next_rec)) { - goto skip_lock; + if (page_rec_is_supremum(page, next_rec)) { + goto next_rec; } lock_type = LOCK_REC_NOT_GAP; @@ -1846,6 +1845,10 @@ row_sel( lock_type = LOCK_ORDINARY; } + offsets = rec_get_offsets(next_rec, index, offsets, + index->n_core_fields, + ULINT_UNDEFINED, &heap); + err = sel_set_rec_lock(&plan->pcur, next_rec, index, offsets, node->row_lock_mode, @@ -1866,8 +1869,7 @@ row_sel( } } -skip_lock: - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(page, rec)) { /* The infimum record on a page cannot be in the result set, and neither can a record lock be placed on it: we skip such @@ -1889,17 +1891,13 @@ row_sel( /* Try to place a lock on the index record */ unsigned lock_type; - offsets = rec_get_offsets(rec, index, offsets, - index->n_core_fields, - ULINT_UNDEFINED, &heap); - /* At READ UNCOMMITTED or READ COMMITTED isolation level, we lock only the record, i.e., next-key locking is not used. */ if (trx->isolation_level <= TRX_ISO_READ_COMMITTED || dict_index_is_spatial(index)) { - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { goto next_rec; } @@ -1909,6 +1907,10 @@ row_sel( lock_type = LOCK_ORDINARY; } + offsets = rec_get_offsets(rec, index, offsets, + index->n_core_fields, + ULINT_UNDEFINED, &heap); + err = sel_set_rec_lock(&plan->pcur, rec, index, offsets, node->row_lock_mode, lock_type, @@ -1925,7 +1927,7 @@ row_sel( } } - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { /* A page supremum record cannot be in the result set: skip it now when we have placed a possible lock on it */ @@ -1933,7 +1935,7 @@ row_sel( goto next_rec; } - ut_ad(page_rec_is_user_rec(rec)); + ut_ad(page_rec_is_user_rec(page, rec)); if (cost_counter > SEL_COST_LIMIT) { @@ -2039,7 +2041,8 @@ row_sel( rec = old_vers; } } else if (!srv_read_only_mode) { - trx_id_t trx_id = page_get_max_trx_id(page_align(rec)); + trx_id_t trx_id = page_get_max_trx_id( + btr_pcur_get_page(&plan->pcur)); ut_ad(trx_id); if (!node->read_view->sees(trx_id)) { cons_read_requires_clust_rec = TRUE; @@ -2182,13 +2185,9 @@ row_sel( goto commit_mtr_for_a_while; } - if (node->asc) { - moved = btr_pcur_move_to_next(&(plan->pcur), &mtr); - } else { - moved = btr_pcur_move_to_prev(&(plan->pcur), &mtr); - } - - if (!moved) { + if (!(node->asc + ? btr_pcur_move_to_next(&plan->pcur, &mtr) + : btr_pcur_move_to_prev(&plan->pcur, &mtr))) { goto table_exhausted; } @@ -3398,7 +3397,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( /* Note: only if the search ends up on a non-infimum record is the low_match value the real match to the search tuple */ - if (!page_rec_is_user_rec(clust_rec) + if (!page_rec_is_user_rec(btr_pcur_get_page(prebuilt->clust_pcur), + clust_rec) || btr_pcur_get_low_match(prebuilt->clust_pcur) < dict_index_get_n_unique(clust_index)) { btr_cur_t* btr_cur = btr_pcur_get_btr_cur(prebuilt->pcur); @@ -3535,9 +3535,11 @@ Row_sel_get_clust_rec_for_mysql::operator()( case DB_SUCCESS_LOCKED_REC: const buf_page_t& bpage = btr_pcur_get_block( prebuilt->clust_pcur)->page; + ut_ad(clust_rec + == btr_pcur_get_rec(prebuilt->clust_pcur)); const lsn_t lsn = mach_read_from_8( - page_align(clust_rec) + FIL_PAGE_LSN); + bpage.frame + FIL_PAGE_LSN); if (lsn != cached_lsn || bpage.id() != cached_page_id @@ -3978,7 +3980,8 @@ row_sel_try_search_shortcut_for_mysql( rec = btr_pcur_get_rec(pcur); - if (!page_rec_is_user_rec(rec) || rec_is_metadata(rec, *index)) { + if (!page_rec_is_user_rec(btr_pcur_get_page(pcur), rec) + || rec_is_metadata(rec, *index)) { return SEL_RETRY; } @@ -4810,12 +4813,13 @@ row_search_mvcc( if (!moves_up && set_also_gap_locks - && !page_rec_is_supremum(rec) + && !page_rec_is_supremum(btr_pcur_get_page(pcur), rec) && !dict_index_is_spatial(index)) { /* Try to place a gap lock on the next index record to prevent phantoms in ORDER BY ... DESC queries */ - const rec_t* next_rec = page_rec_get_next_const(rec); + const rec_t* next_rec = page_rec_get_next( + btr_pcur_get_page(pcur), rec); if (UNIV_UNLIKELY(!next_rec)) { err = DB_CORRUPTION; goto page_corrupted; @@ -4914,11 +4918,12 @@ row_search_mvcc( /* PHASE 4: Look for matching records in a loop */ rec = btr_pcur_get_rec(pcur); + const page_t* page = btr_pcur_get_page(pcur); - ut_ad(!!page_rec_is_comp(rec) == comp); - ut_ad(page_rec_is_leaf(rec)); + ut_ad(!!page_is_comp(page) == comp); + ut_ad(page_is_leaf(page)); - if (page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(page, rec)) { /* The infimum record on a page cannot be in the result set, and neither can a record lock be placed on it: we skip such @@ -4927,7 +4932,7 @@ row_search_mvcc( goto next_rec; } - if (page_rec_is_supremum(rec)) { + if (page_rec_is_supremum(page, rec)) { if (set_also_gap_locks && !dict_index_is_spatial(index)) { @@ -5005,8 +5010,8 @@ row_search_mvcc( .buf_fix_count(); ib::error() << "Index corruption: rec offs " - << page_offset(rec) << " next offs " - << next_offs + << rec - btr_pcur_get_page(pcur) + << " next offs " << next_offs << btr_pcur_get_block(pcur)->page.id() << ", index " << index->name << " of table " << index->table->name @@ -5022,8 +5027,8 @@ row_search_mvcc( over the corruption to recover as much as possible. */ ib::info() << "Index corruption: rec offs " - << page_offset(rec) << " next offs " - << next_offs + << rec - btr_pcur_get_page(pcur) + << " next offs " << next_offs << btr_pcur_get_block(pcur)->page.id() << ", index " << index->name << " of table " << index->table->name @@ -5039,18 +5044,18 @@ row_search_mvcc( /* Calculate the 'offsets' associated with 'rec' */ - ut_ad(fil_page_index_page_check(btr_pcur_get_page(pcur))); - ut_ad(btr_page_get_index_id(btr_pcur_get_page(pcur)) == index->id); + ut_ad(fil_page_index_page_check(page)); + ut_ad(btr_page_get_index_id(page) == index->id); offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); if (UNIV_UNLIKELY(srv_force_recovery > 0)) { if (!rec_validate(rec, offsets) - || !btr_index_rec_validate(rec, index, FALSE)) { + || !btr_index_rec_validate(page, rec, index, false)) { ib::error() << "Index corruption: rec offs " - << page_offset(rec) << " next offs " + << rec - page << " next offs " << next_offs << btr_pcur_get_block(pcur)->page.id() << ", index " << index->name @@ -6276,7 +6281,7 @@ dberr_t row_check_index(row_prebuilt_t *prebuilt, ulint *n_rows) const rec_t *rec= btr_pcur_get_rec(prebuilt->pcur); rec_offs *offsets= offsets_; - if (page_rec_is_supremum(rec)) + if (btr_pcur_is_after_last_on_page(prebuilt->pcur)) { next_page: if (btr_pcur_is_after_last_in_tree(prebuilt->pcur)) @@ -6406,8 +6411,9 @@ dberr_t row_check_index(row_prebuilt_t *prebuilt, ulint *n_rows) /* Note: only if the search ends up on a non-infimum record is the low_match value the real match to the search tuple */ - if (!page_rec_is_user_rec(clust_rec) || - btr_pcur_get_low_match(prebuilt->clust_pcur) < clust_index->n_uniq) + if (btr_pcur_get_low_match(prebuilt->clust_pcur) < clust_index->n_uniq || + !page_rec_is_user_rec(btr_pcur_get_page(prebuilt->clust_pcur), + clust_rec)) { if (!rec_deleted) { @@ -6903,7 +6909,7 @@ row_search_get_max_rec( page = btr_pcur_get_page(&pcur); rec = page_find_rec_max_not_deleted(page); - if (page_rec_is_user_rec(rec)) { + if (page_rec_is_user_rec(page, rec)) { break; } else { rec = NULL; diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 52f5444391112..579c5c53cba65 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -445,12 +445,11 @@ row_undo_mod_clust( 0, 1ULL << ROLL_PTR_INSERT_FLAG_POS, &mtr); } else { - size_t offs = page_offset(rec + trx_id_offset); + byte *offs = rec + trx_id_offset; mtr.memset(block, offs, DATA_TRX_ID_LEN, 0); offs += DATA_TRX_ID_LEN; mtr.write<1,mtr_t::MAYBE_NOP>(*block, - block->page.frame - + offs, 0x80U); + offs, 0x80U); mtr.memset(block, offs + 1, DATA_ROLL_PTR_LEN - 1, 0); } diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index f14673c173fd8..8bd7e006e9cd8 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -320,18 +320,19 @@ static buf_block_t* row_undo_rec_get(undo_node_t* node) buf_page_make_young_if_needed(&undo_page->page); - uint16_t offset = undo->top_offset; + node->undo_rec = undo_page->page.frame + undo->top_offset; buf_block_t* prev_page = undo_page; if (trx_undo_rec_t* prev_rec = trx_undo_get_prev_rec( - prev_page, offset, undo->hdr_page_no, undo->hdr_offset, + prev_page, node->undo_rec, + undo->hdr_page_no, undo->hdr_offset, true, &mtr)) { if (prev_page != undo_page) { trx->pages_undone++; } undo->top_page_no = prev_page->page.id().page_no(); - undo->top_offset = page_offset(prev_rec); + undo->top_offset = uint16_t(prev_rec - prev_page->page.frame); undo->top_undo_no = trx_undo_rec_get_undo_no(prev_rec); ut_ad(!undo->empty()); } else { @@ -342,10 +343,8 @@ static buf_block_t* row_undo_rec_get(undo_node_t* node) undo_page->fix(); mtr.commit(); - node->undo_rec = undo_page->page.frame + offset; - const size_t end = mach_read_from_2(node->undo_rec); - if (UNIV_UNLIKELY(end <= offset + if (UNIV_UNLIKELY(end <= uint16_t(node->roll_ptr) || end >= srv_page_size - FIL_PAGE_DATA_END)) { undo_page->unfix(); node->undo_rec = nullptr; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index a39574d2f64d9..13fddd4c7532a 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -2201,7 +2201,6 @@ row_upd_clust_rec_by_insert( { mem_heap_t* heap; btr_pcur_t* pcur; - btr_cur_t* btr_cur; trx_t* trx; dict_table_t* table; dtuple_t* entry; @@ -2217,7 +2216,6 @@ row_upd_clust_rec_by_insert( trx = thr_get_trx(thr); table = node->table; pcur = node->pcur; - btr_cur = btr_pcur_get_btr_cur(pcur); heap = mem_heap_create(1000); @@ -2245,11 +2243,11 @@ row_upd_clust_rec_by_insert( /* This is the first invocation of the function where we update the primary key. Delete-mark the old record in the clustered index and prepare to insert a new entry. */ - rec = btr_cur_get_rec(btr_cur); + ut_ad(btr_pcur_is_on_user_rec(pcur)); + rec = btr_pcur_get_rec(pcur); offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); - ut_ad(page_rec_is_user_rec(rec)); if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))) { /* If the clustered index record is already delete @@ -2269,7 +2267,7 @@ row_upd_clust_rec_by_insert( } err = btr_cur_del_mark_set_clust_rec( - btr_cur_get_block(btr_cur), rec, index, offsets, + btr_pcur_get_block(pcur), rec, index, offsets, thr, node->row, mtr); if (err != DB_SUCCESS) { goto err_exit; @@ -2289,7 +2287,7 @@ row_upd_clust_rec_by_insert( insert fails, then this disown will be undone when the operation is rolled back. */ btr_cur_disown_inherited_fields( - btr_cur_get_block(btr_cur), + btr_pcur_get_block(pcur), rec, index, offsets, node->update, mtr); } @@ -2651,7 +2649,9 @@ row_upd_clust_step( || row_get_rec_trx_id(rec, index, offsets) == trx->id || lock_trx_has_expl_x_lock(*trx, *index->table, btr_pcur_get_block(pcur)->page.id(), - page_rec_get_heap_no(rec))); + page_rec_get_heap_no( + btr_pcur_get_page(pcur), + rec))); if (node->is_delete == PLAIN_DELETE) { err = row_upd_del_mark_clust_rec( diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 4d826bb041213..f8848e641222f 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -463,10 +463,13 @@ static ulint trx_rseg_get_n_undo_tablespaces() mtr.start(); if (const buf_block_t *sys_header= trx_sysf_get(&mtr, false)) + { + const page_t *sys_page= sys_header->page.frame; for (ulint rseg_id= 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) - if (trx_sysf_rseg_get_page_no(sys_header, rseg_id) != FIL_NULL) - if (uint32_t space= trx_sysf_rseg_get_space(sys_header, rseg_id)) + if (trx_sysf_rseg_get_page_no(sys_page, rseg_id) != FIL_NULL) + if (uint32_t space= trx_sysf_rseg_get_space(sys_page, rseg_id)) space_ids.insert(space); + } mtr.commit(); return space_ids.size(); } @@ -1789,7 +1792,8 @@ dberr_t srv_start(bool create_new_db) mtr.commit(); return srv_init_abort(DB_CORRUPTION); } - fil_block_check_type(*block, FIL_PAGE_TYPE_SYS, &mtr); + fil_block_check_type(*block, block->page.frame, + FIL_PAGE_TYPE_SYS, &mtr); /* Already MySQL 3.23.53 initialized FSP_IBUF_TREE_ROOT_PAGE_NO to FIL_PAGE_INDEX. No need to reset that one. */ @@ -1799,8 +1803,8 @@ dberr_t srv_start(bool create_new_db) if (UNIV_UNLIKELY(!block)) { goto corrupted_old_page; } - fil_block_check_type(*block, FIL_PAGE_TYPE_TRX_SYS, - &mtr); + fil_block_check_type(*block, block->page.frame, + FIL_PAGE_TYPE_TRX_SYS, &mtr); block = buf_page_get( page_id_t(TRX_SYS_SPACE, FSP_FIRST_RSEG_PAGE_NO), @@ -1808,14 +1812,16 @@ dberr_t srv_start(bool create_new_db) if (UNIV_UNLIKELY(!block)) { goto corrupted_old_page; } - fil_block_check_type(*block, FIL_PAGE_TYPE_SYS, &mtr); + fil_block_check_type(*block, block->page.frame, + FIL_PAGE_TYPE_SYS, &mtr); block = buf_page_get( page_id_t(TRX_SYS_SPACE, FSP_DICT_HDR_PAGE_NO), 0, RW_X_LATCH, &mtr); if (UNIV_UNLIKELY(!block)) { goto corrupted_old_page; } - fil_block_check_type(*block, FIL_PAGE_TYPE_SYS, &mtr); + fil_block_check_type(*block, block->page.frame, + FIL_PAGE_TYPE_SYS, &mtr); mtr.commit(); } diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 2dc39118d3ddf..aaa019952b899 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -639,7 +639,7 @@ fill_lock_data( return(TRUE); } - page = reinterpret_cast(buf_block_get_frame(block)); + page = block->page.frame; rec_offs_init(offsets_onstack); offsets = offsets_onstack; diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 00cd2b89e3a78..8801c5e0003f0 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -160,6 +160,38 @@ TRANSACTIONAL_TARGET bool purge_sys_t::is_purgeable(trx_id_t trx_id) const return purgeable; } +/** Update the offset information about the end of the binlog entry +which corresponds to the transaction just being committed. +In a replication slave, this updates the master binlog position +up to which replication has proceeded. +@param rseg_header rollback segment header +@param rseg_header_page rollback segment header page +@param trx committing transaction +@param mtr mini-transaction */ +static void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, + page_t *rseg_header_page, + const trx_t *trx, mtr_t *mtr) +{ + DBUG_PRINT("trx", ("trx_mysql_binlog_offset: %llu", trx->mysql_log_offset)); + + const size_t len= strlen(trx->mysql_log_file_name) + 1; + + ut_ad(len > 1); + + if (UNIV_UNLIKELY(len > TRX_RSEG_BINLOG_NAME_LEN)) + return; + + mtr->write<8,mtr_t::MAYBE_NOP>(*rseg_header, + TRX_RSEG + TRX_RSEG_BINLOG_OFFSET + + rseg_header_page, + trx->mysql_log_offset); + + void *name= TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_header_page; + + if (memcmp(trx->mysql_log_file_name, name, len)) + mtr->memcpy(*rseg_header, name, trx->mysql_log_file_name, len); +} + /*================ UNDO LOG HISTORY LIST =============================*/ /** Prepend the history list with an undo log. @@ -188,7 +220,9 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) /* This function is invoked during transaction commit, which is not allowed to fail. If we get a corrupted undo header, we will crash here. */ ut_a(undo_page); - trx_ulogf_t *undo_header= undo_page->page.frame + undo->hdr_offset; + page_t *const upage= undo_page->page.frame; + page_t *const rseg_header_page= rseg_header->page.frame; + trx_ulogf_t *const undo_header= upage + undo->hdr_offset; ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1); ut_ad(rseg->needs_purge > trx->id); @@ -197,16 +231,15 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) rseg->history_size++; if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + - rseg_header->page.frame))) + rseg_header_page))) /* This database must have been upgraded from before MariaDB 10.3.5. */ - trx_rseg_format_upgrade(rseg_header, mtr); + trx_rseg_format_upgrade(rseg_header, rseg_header_page, mtr); uint16_t undo_state; if (undo->size == 1 && TRX_UNDO_PAGE_REUSE_LIMIT > - mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + - undo_page->page.frame)) + mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + upage)) { undo->state= undo_state= TRX_UNDO_CACHED; UT_LIST_ADD_FIRST(rseg->undo_cached, undo); @@ -214,17 +247,17 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) else { ut_ad(undo->size == flst_get_len(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + - undo_page->page.frame)); + upage)); /* The undo log segment will not be reused */ static_assert(FIL_NULL == 0xffffffff, ""); mtr->memset(rseg_header, TRX_RSEG + TRX_RSEG_UNDO_SLOTS + - undo->id * TRX_RSEG_SLOT_SIZE, 4, 0xff); + undo->id * TRX_RSEG_SLOT_SIZE + rseg_header_page, 4, 0xff); uint32_t hist_size= mach_read_from_4(TRX_RSEG_HISTORY_SIZE + TRX_RSEG + - rseg_header->page.frame); + rseg_header_page); mtr->write<4>(*rseg_header, TRX_RSEG + TRX_RSEG_HISTORY_SIZE + - rseg_header->page.frame, hist_size + undo->size); + rseg_header_page, hist_size + undo->size); mtr->write<8>(*rseg_header, TRX_RSEG + TRX_RSEG_MAX_TRX_ID + - rseg_header->page.frame, trx_sys.get_max_trx_id()); + rseg_header_page, trx_sys.get_max_trx_id()); ut_free(undo); undo_state= TRX_UNDO_TO_PURGE; } @@ -250,13 +283,14 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) #ifdef WITH_WSREP if (wsrep_is_wsrep_xid(&trx->xid)) - trx_rseg_update_wsrep_checkpoint(rseg_header, &trx->xid, mtr); + trx_rseg_update_wsrep_checkpoint(rseg_header, rseg_header_page, + &trx->xid, mtr); #endif if (trx->mysql_log_file_name && *trx->mysql_log_file_name) /* Update the latest binlog name and offset if log_bin=ON or this is a replica. */ - trx_rseg_update_binlog_offset(rseg_header, trx, mtr); + trx_rseg_update_binlog_offset(rseg_header, rseg_header_page, trx, mtr); /* Add the log as the first in the history list */ @@ -264,13 +298,13 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) when detecting corruption. It is better to crash the server than to intentionally violate ACID by committing something that is known to be corrupted. */ - ut_a(flst_add_first(rseg_header, TRX_RSEG + TRX_RSEG_HISTORY, undo_page, - uint16_t(page_offset(undo_header) + - TRX_UNDO_HISTORY_NODE), rseg->space->free_limit, - mtr) == DB_SUCCESS); + ut_a(flst_add_first(rseg_header, TRX_RSEG + TRX_RSEG_HISTORY + + rseg_header_page, undo_page, + undo_header + TRX_UNDO_HISTORY_NODE, + rseg->space->free_limit, mtr) == DB_SUCCESS); - mtr->write<2>(*undo_page, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + - undo_page->page.frame, undo_state); + mtr->write<2>(*undo_page, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + upage, + undo_state); mtr->write<8,mtr_t::MAYBE_NOP>(*undo_page, undo_header + TRX_UNDO_TRX_NO, trx->rw_trx_hash_element->no); mtr->write<2,mtr_t::MAYBE_NOP>(*undo_page, undo_header + @@ -287,8 +321,10 @@ static void trx_purge_free_segment(buf_block_t *rseg_hdr, buf_block_t *block, ut_ad(mtr.memo_contains_flagged(rseg_hdr, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr.memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); - while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + - block->page.frame, &mtr)) + byte *fseg_header= TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + + block->page.frame; + + while (!fseg_free_step_not_header(fseg_header, &mtr)) { rseg_hdr->fix(); block->fix(); @@ -311,8 +347,7 @@ static void trx_purge_free_segment(buf_block_t *rseg_hdr, buf_block_t *block, mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX); } - while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + - block->page.frame, &mtr)); + while (!fseg_free_step(fseg_header, &mtr)); } void purge_sys_t::rseg_enable(trx_rseg_t &rseg) @@ -384,7 +419,8 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const return err; } - hdr_addr= flst_get_last(TRX_RSEG + TRX_RSEG_HISTORY + rseg_hdr->page.frame); + page_t *const rseg_hdr_page= rseg_hdr->page.frame; + hdr_addr= flst_get_last(TRX_RSEG + TRX_RSEG_HISTORY + rseg_hdr_page); if (hdr_addr.page == FIL_NULL) goto func_exit; @@ -409,8 +445,9 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const if (!b) goto func_exit; + page_t *const page= b->page.frame; const trx_id_t undo_trx_no= - mach_read_from_8(b->page.frame + hdr_addr.boffset + TRX_UNDO_TRX_NO); + mach_read_from_8(page + hdr_addr.boffset + TRX_UNDO_TRX_NO); if (undo_trx_no >= trx_no) { @@ -448,7 +485,7 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const } fil_addr_t prev_hdr_addr= - flst_get_prev_addr(b->page.frame + hdr_addr.boffset + + flst_get_prev_addr(page + hdr_addr.boffset + TRX_UNDO_HISTORY_NODE); if (prev_hdr_addr.page == FIL_NULL); else if (prev_hdr_addr.page >= last_page || @@ -459,25 +496,24 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const prev_hdr_addr.boffset= static_cast(prev_hdr_addr.boffset - TRX_UNDO_HISTORY_NODE); - err= flst_remove(rseg_hdr, TRX_RSEG + TRX_RSEG_HISTORY, b, - uint16_t(hdr_addr.boffset + TRX_UNDO_HISTORY_NODE), + err= flst_remove(rseg_hdr, TRX_RSEG + TRX_RSEG_HISTORY + rseg_hdr_page, b, + page + hdr_addr.boffset + TRX_UNDO_HISTORY_NODE, last_page, &mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) goto func_exit; rseg_hdr->fix(); - if (mach_read_from_2(b->page.frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) + if (mach_read_from_2(page + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) /* We cannot free the entire undo log segment. */; else { const uint32_t seg_size= - flst_get_len(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + b->page.frame); - switch (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + - b->page.frame)) { + flst_get_len(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + page); + switch (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + page)) { case TRX_UNDO_TO_PURGE: { - byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame; + byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr_page; ut_ad(mach_read_from_4(hist) >= seg_size); mtr.write<4>(*rseg_hdr, hist, mach_read_from_4(hist) - seg_size); } @@ -498,13 +534,13 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const UT_LIST_REMOVE(rseg.undo_cached, undo); static_assert(FIL_NULL == 0xffffffff, ""); if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + - rseg_hdr->page.frame))) - trx_rseg_format_upgrade(rseg_hdr, &mtr); + rseg_hdr_page))) + trx_rseg_format_upgrade(rseg_hdr, rseg_hdr_page, &mtr); mtr.memset(rseg_hdr, TRX_RSEG + TRX_RSEG_UNDO_SLOTS + - undo->id * TRX_RSEG_SLOT_SIZE, 4, 0xff); + undo->id * TRX_RSEG_SLOT_SIZE + rseg_hdr_page, 4, 0xff); ut_free(undo); mtr.write<8,mtr_t::MAYBE_NOP>(*rseg_hdr, TRX_RSEG + TRX_RSEG_MAX_TRX_ID + - rseg_hdr->page.frame, + rseg_hdr_page, trx_sys.get_max_trx_id() - 1); goto free_segment; } @@ -908,11 +944,12 @@ bool purge_sys_t::choose_next_log() buf_block_t *b= get_page(id); if (!b) goto purge_nothing; + const byte *const hoffset= b->page.frame + hdr_offset; const trx_undo_rec_t *undo_rec= - trx_undo_page_get_first_rec(b, hdr_page_no, hdr_offset); + trx_undo_page_get_first_rec(b, hdr_page_no, hoffset); if (!undo_rec) { - if (mach_read_from_2(b->page.frame + hdr_offset + TRX_UNDO_NEXT_LOG)) + if (mach_read_from_2(hoffset + TRX_UNDO_NEXT_LOG)) goto purge_nothing; const uint32_t next= mach_read_from_4(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + @@ -924,12 +961,14 @@ bool purge_sys_t::choose_next_log() if (!b) goto purge_nothing; undo_rec= - trx_undo_page_get_first_rec(b, hdr_page_no, hdr_offset); + trx_undo_page_get_first_rec(b, hdr_page_no, + b->page.frame + hdr_offset); if (!undo_rec) goto purge_nothing; } - offset= page_offset(undo_rec); + ut_ad(b->page.frame == page_align(undo_rec)); + offset= uint16_t(undo_rec - b->page.frame); tail.undo_no= trx_undo_rec_get_undo_no(undo_rec); page_no= id.page_no(); } @@ -949,6 +988,8 @@ inline trx_purge_rec_t purge_sys_t::get_next_rec(roll_ptr_t roll_ptr) ut_ad(next_stored); ut_ad(tail.trx_no < low_limit_no()); ut_ad(rseg->latch.have_wr()); + ut_ad(uint16_t(roll_ptr) >= FIL_PAGE_DATA); + ut_ad(uint16_t(roll_ptr) < srv_page_size - FIL_PAGE_DATA_END); if (!offset) { @@ -971,28 +1012,31 @@ inline trx_purge_rec_t purge_sys_t::get_next_rec(roll_ptr_t roll_ptr) return {nullptr, 0}; } + const page_t *frame= b->page.frame; + if (const trx_undo_rec_t *rec2= - trx_undo_page_get_next_rec(b, offset, hdr_page_no, hdr_offset)) + trx_undo_page_get_next_rec(b, frame + offset, hdr_page_no, hdr_offset)) { + offset= uint16_t(rec2 - frame); got_rec: - ut_ad(page_no == page_id.page_no()); - offset= page_offset(rec2); tail.undo_no= trx_undo_rec_get_undo_no(rec2); } else if (hdr_page_no != page_no || - !mach_read_from_2(b->page.frame + hdr_offset + TRX_UNDO_NEXT_LOG)) + !mach_read_from_2(frame + hdr_offset + TRX_UNDO_NEXT_LOG)) { uint32_t next= mach_read_from_4(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + - FLST_NEXT + FIL_ADDR_PAGE + b->page.frame); + FLST_NEXT + FIL_ADDR_PAGE + frame); if (next != FIL_NULL) { page_id.set_page_no(next); if (buf_block_t *next_page= get_page(page_id)) { - rec2= trx_undo_page_get_first_rec(next_page, hdr_page_no, hdr_offset); + rec2= trx_undo_page_get_first_rec(next_page, hdr_page_no, + next_page->page.frame + hdr_offset); if (rec2) { page_no= next; + offset= uint16_t(rec2 - next_page->page.frame); goto got_rec; } } @@ -1009,7 +1053,7 @@ inline trx_purge_rec_t purge_sys_t::get_next_rec(roll_ptr_t roll_ptr) if (locked) rseg->latch.wr_unlock(); - return {b->page.frame + uint16_t(roll_ptr), roll_ptr}; + return {frame + uint16_t(roll_ptr), roll_ptr}; } inline trx_purge_rec_t purge_sys_t::fetch_next_rec() diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index e05c018c7348c..704e38202cd35 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -55,17 +55,15 @@ const dtuple_t trx_undo_metadata = { /*=========== UNDO LOG RECORD CREATION AND DECODING ====================*/ /** Calculate the free space left for extending an undo log record. -@param undo_block undo log page @param ptr current end of the undo page @return bytes left */ -static ulint trx_undo_left(const buf_block_t *undo_block, const byte *ptr) +static ulint trx_undo_left(const byte *ptr) { - ut_ad(ptr >= - &undo_block->page.frame[TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE]); + const ulint offset= page_offset(ptr); + ut_ad(offset >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); /* The 10 is supposed to be an extra safety margin (and needed for compatibility with older versions) */ - lint left= srv_page_size - (ptr - undo_block->page.frame) - - (10 + FIL_PAGE_DATA_END); + lint left= srv_page_size - offset - (10 + FIL_PAGE_DATA_END); ut_ad(left >= 0); return left < 0 ? 0 : static_cast(left); } @@ -84,14 +82,16 @@ trx_undo_page_set_next_prev_and_add( written on this undo page. */ mtr_t* mtr) /*!< in: mtr */ { - ut_ad(page_align(ptr) == undo_block->page.frame); + page_t *const undo_page= page_align(ptr); + + ut_ad(undo_page == undo_block->page.frame); - if (UNIV_UNLIKELY(trx_undo_left(undo_block, ptr) < 2)) + if (UNIV_UNLIKELY(trx_undo_left(ptr) < 2)) return 0; byte *ptr_to_first_free= my_assume_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + - undo_block->page.frame); + undo_page); const uint16_t first_free= mach_read_from_2(ptr_to_first_free); @@ -99,14 +99,13 @@ trx_undo_page_set_next_prev_and_add( memcpy(ptr, ptr_to_first_free, 2); ptr += 2; - const uint16_t end_of_rec= static_cast - (ptr - undo_block->page.frame); + const uint16_t end_of_rec= uint16_t(ptr - undo_page); /* Update the offset to first free undo record */ mach_write_to_2(ptr_to_first_free, end_of_rec); /* Write offset of the next undo log record */ - memcpy(undo_block->page.frame + first_free, ptr_to_first_free, 2); - const byte *start= undo_block->page.frame + first_free + 2; + memcpy(undo_page + first_free, ptr_to_first_free, 2); + const byte *start= undo_page + first_free + 2; mtr->undo_append(*undo_block, start, ptr - start - 2); return first_free; @@ -134,6 +133,7 @@ trx_undo_log_v_idx( byte* ptr, bool first_v_col) { + ut_ad(page_align(ptr) == undo_block->page.frame); ut_ad(pos < table->n_v_def); dict_v_col_t* vcol = dict_table_get_nth_v_col(table, pos); byte* old_ptr; @@ -141,7 +141,7 @@ trx_undo_log_v_idx( ut_ad(!vcol->v_indexes.empty()); ulint size = first_v_col ? 1 + 2 : 2; - const ulint avail = trx_undo_left(undo_block, ptr); + const ulint avail = trx_undo_left(ptr); /* The mach_write_compressed(ptr, flen) in trx_undo_page_report_modify() will consume additional 1 to 5 bytes. */ @@ -305,7 +305,9 @@ trx_undo_report_insert_virtual( byte* start = *ptr; bool first_v_col = true; - if (trx_undo_left(undo_block, *ptr) < 2) { + ut_ad(page_align(*ptr) == undo_block->page.frame); + + if (trx_undo_left(*ptr) < 2) { return(false); } @@ -322,7 +324,7 @@ trx_undo_report_insert_virtual( if (col->m_col.ord_part) { /* make sure enought space to write the length */ - if (trx_undo_left(undo_block, *ptr) < 5) { + if (trx_undo_left(*ptr) < 5) { return(false); } @@ -342,7 +344,7 @@ trx_undo_report_insert_virtual( row, col->v_pos); switch (ulint flen = vfield->len) { case 0: case UNIV_SQL_NULL: - if (trx_undo_left(undo_block, *ptr) < 5) { + if (trx_undo_left(*ptr) < 5) { return(false); } @@ -357,8 +359,7 @@ trx_undo_report_insert_virtual( flen = max_len; } - if (trx_undo_left(undo_block, *ptr) - < flen + 5) { + if (trx_undo_left(*ptr) < flen + 5) { return(false); } *ptr += mach_write_compressed(*ptr, flen); @@ -377,6 +378,7 @@ trx_undo_report_insert_virtual( /** Reports in the undo log of an insert of a clustered index record. @param undo_block undo log page +@param undo_page undo log page frame @param trx transaction @param index clustered index @param clust_entry index entry which will be inserted to the @@ -388,6 +390,7 @@ static uint16_t trx_undo_page_report_insert( buf_block_t* undo_block, + page_t* undo_page, trx_t* trx, dict_index_t* index, const dtuple_t* clust_entry, @@ -400,30 +403,30 @@ trx_undo_page_report_insert( TRX_UNDO_INSERT == 1 into insert_undo pages, or TRX_UNDO_UPDATE == 2 into update_undo pages. */ ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE - + undo_block->page.frame) <= 2); + + undo_page) <= 2); uint16_t first_free = mach_read_from_2(my_assume_aligned<2> (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->page.frame)); - byte* ptr = undo_block->page.frame + first_free; + + undo_page)); + byte* ptr = undo_page + first_free; + byte* const ptr_to_type = &ptr[2]; - if (trx_undo_left(undo_block, ptr) < 2 + 1 + 11 + 11) { + if (trx_undo_left(ptr) < 2 + 1 + 11 + 11) { /* Not enough space for writing the general parameters */ return(0); } /* Reserve 2 bytes for the pointer to the next undo log record */ - ptr += 2; + ptr += 3; /* Store first some general parameters to the undo log */ - *ptr++ = TRX_UNDO_INSERT_REC; ptr += mach_u64_write_much_compressed(ptr, trx->undo_no); ptr += mach_u64_write_much_compressed(ptr, index->table->id); if (write_empty) { /* Table is in bulk operation */ - undo_block->page.frame[first_free + 2] = TRX_UNDO_EMPTY; + *ptr_to_type = TRX_UNDO_EMPTY; goto done; } @@ -433,19 +436,18 @@ trx_undo_page_report_insert( if (UNIV_UNLIKELY(clust_entry->info_bits != 0)) { ut_ad(clust_entry->is_metadata()); ut_ad(index->is_instant()); - ut_ad(undo_block->page.frame[first_free + 2] - == TRX_UNDO_INSERT_REC); - undo_block->page.frame[first_free + 2] - = TRX_UNDO_INSERT_METADATA; + *ptr_to_type = TRX_UNDO_INSERT_METADATA; goto done; } + *ptr_to_type = TRX_UNDO_INSERT_REC; + for (unsigned i = 0; i < dict_index_get_n_unique(index); i++) { const dfield_t* field = dtuple_get_nth_field(clust_entry, i); ulint flen = dfield_get_len(field); - if (trx_undo_left(undo_block, ptr) < 5) { + if (trx_undo_left(ptr) < 5) { return(0); } @@ -456,7 +458,7 @@ trx_undo_page_report_insert( case 0: case UNIV_SQL_NULL: break; default: - if (trx_undo_left(undo_block, ptr) < flen) { + if (trx_undo_left(ptr) < flen) { return(0); } @@ -772,6 +774,7 @@ uint16_t trx_undo_page_report_modify( /*========================*/ buf_block_t* undo_block, /*!< in: undo log page */ + page_t* undo_page, /*!< in: undo log page frame */ trx_t* trx, /*!< in: transaction */ dict_index_t* index, /*!< in: clustered index where update or delete marking is done */ @@ -794,16 +797,15 @@ trx_undo_page_report_modify( TRX_UNDO_INSERT == 1 into insert_undo pages, or TRX_UNDO_UPDATE == 2 into update_undo pages. */ ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE - + undo_block->page.frame) <= 2); + + undo_page) <= 2); byte* ptr_to_first_free = my_assume_aligned<2>( - TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->page.frame); + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + undo_page); const uint16_t first_free = mach_read_from_2(ptr_to_first_free); - byte *ptr = undo_block->page.frame + first_free; + byte *ptr = undo_page + first_free; - if (trx_undo_left(undo_block, ptr) < 50) { + if (trx_undo_left(ptr) < 50) { /* NOTE: the value 50 must be big enough so that the general fields written below fit on the undo log page */ return 0; @@ -893,14 +895,14 @@ trx_undo_page_report_modify( ut_ad(!rec_offs_nth_extern(offsets, i)); ut_ad(dict_index_get_nth_col(index, i)->ord_part); - if (trx_undo_left(undo_block, ptr) < 5) { + if (trx_undo_left(ptr) < 5) { return(0); } ptr += mach_write_compressed(ptr, flen); if (flen != UNIV_SQL_NULL) { - if (trx_undo_left(undo_block, ptr) < flen) { + if (trx_undo_left(ptr) < flen) { return(0); } @@ -913,7 +915,7 @@ trx_undo_page_report_modify( /* Save to the undo log the old values of the columns to be updated. */ if (update) { - if (trx_undo_left(undo_block, ptr) < 5) { + if (trx_undo_left(ptr) < 5) { return(0); } @@ -958,7 +960,7 @@ trx_undo_page_report_modify( ptr += mach_write_compressed(ptr, n_updated); for (; i < upd_get_n_fields(update); i++) { - if (trx_undo_left(undo_block, ptr) < 5) { + if (trx_undo_left(ptr) < 5) { return 0; } @@ -984,7 +986,7 @@ trx_undo_page_report_modify( ptr += mach_write_compressed( ptr, pos + REC_MAX_N_FIELDS); - if (trx_undo_left(undo_block, ptr) < 15) { + if (trx_undo_left(ptr) < 15) { return 0; } @@ -1062,7 +1064,7 @@ trx_undo_page_report_modify( /* Write field number to undo log */ ptr += mach_write_compressed(ptr, pos); - if (trx_undo_left(undo_block, ptr) < 15) { + if (trx_undo_left(ptr) < 15) { return 0; } @@ -1097,7 +1099,7 @@ trx_undo_page_report_modify( } if (flen != UNIV_SQL_NULL) { - if (trx_undo_left(undo_block, ptr) < flen) { + if (trx_undo_left(ptr) < flen) { return(0); } @@ -1114,15 +1116,14 @@ trx_undo_page_report_modify( flen, max_v_log_len); } - if (trx_undo_left(undo_block, ptr) < 15) { + if (trx_undo_left(ptr) < 15) { return(0); } ptr += mach_write_compressed(ptr, flen); if (flen != UNIV_SQL_NULL) { - if (trx_undo_left(undo_block, ptr) - < flen) { + if (trx_undo_left(ptr) < flen) { return(0); } @@ -1156,7 +1157,7 @@ trx_undo_page_report_modify( double mbr[SPDIMS * 2]; mem_heap_t* row_heap = NULL; - if (trx_undo_left(undo_block, ptr) < 5) { + if (trx_undo_left(ptr) < 5) { return(0); } @@ -1222,7 +1223,7 @@ trx_undo_page_report_modify( if (true) { /* Write field number to undo log */ - if (trx_undo_left(undo_block, ptr) < 5 + 15) { + if (trx_undo_left(ptr) < 5 + 15) { return(0); } @@ -1270,8 +1271,7 @@ trx_undo_page_report_modify( if (flen != UNIV_SQL_NULL && spatial_status != SPATIAL_ONLY) { - if (trx_undo_left(undo_block, ptr) - < flen) { + if (trx_undo_left(ptr) < flen) { return(0); } @@ -1280,8 +1280,7 @@ trx_undo_page_report_modify( } if (spatial_status != SPATIAL_NONE) { - if (trx_undo_left(undo_block, ptr) - < DATA_MBR_LEN) { + if (trx_undo_left(ptr) < DATA_MBR_LEN) { return(0); } @@ -1311,7 +1310,7 @@ trx_undo_page_report_modify( /* Write field number to undo log. Make sure there is enought space in log */ - if (trx_undo_left(undo_block, ptr) < 5) { + if (trx_undo_left(ptr) < 5) { return(0); } @@ -1364,8 +1363,7 @@ trx_undo_page_report_modify( case 0: case UNIV_SQL_NULL: break; default: - if (trx_undo_left(undo_block, ptr) - < flen) { + if (trx_undo_left(ptr) < flen) { return(0); } @@ -1384,18 +1382,17 @@ trx_undo_page_report_modify( /*----------------------------------------*/ /* Write pointers to the previous and the next undo log records */ - if (trx_undo_left(undo_block, ptr) < 2) { + if (trx_undo_left(ptr) < 2) { return(0); } mach_write_to_2(ptr, first_free); - const uint16_t new_free = static_cast( - ptr + 2 - undo_block->page.frame); - mach_write_to_2(undo_block->page.frame + first_free, new_free); + const uint16_t new_free = static_cast(ptr + 2 - undo_page); + mach_write_to_2(undo_page + first_free, new_free); mach_write_to_2(ptr_to_first_free, new_free); - const byte* start = &undo_block->page.frame[first_free + 2]; + const byte* start = &undo_page[first_free + 2]; mtr->undo_append(*undo_block, start, ptr - start); return(first_free); } @@ -1674,13 +1671,14 @@ uint16_t trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table, buf_block_t* block, mtr_t* mtr) { + page_t* page = block->page.frame; byte* ptr_first_free = my_assume_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + block->page.frame); + + page); const uint16_t first_free = mach_read_from_2(ptr_first_free); ut_ad(first_free >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); ut_ad(first_free <= srv_page_size - FIL_PAGE_DATA_END); - byte* const start = block->page.frame + first_free; + byte* const start = page + first_free; size_t len = strlen(table->name.m_name); const size_t fixed = 2 + 1 + 11 + 11 + 2; ut_ad(len <= NAME_CHAR_LEN * 5 * 2 + 1); @@ -1689,7 +1687,7 @@ trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table, + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE < UNIV_PAGE_SIZE_MIN - 10 - FIL_PAGE_DATA_END); - if (trx_undo_left(block, start) < fixed + len) { + if (trx_undo_left(start) < fixed + len) { ut_ad(first_free > TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); return 0; @@ -1702,7 +1700,7 @@ trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table, memcpy(ptr, table->name.m_name, len); ptr += len; mach_write_to_2(ptr, first_free); - mach_write_to_2(ptr_first_free, ptr + 2 - block->page.frame); + mach_write_to_2(ptr_first_free, ptr + 2 - page); memcpy(start, ptr_first_free, 2); mtr->undo_append(*block, start + 2, ptr - start - 2); return first_free; @@ -1902,19 +1900,21 @@ trx_undo_report_row_operation( ut_ad(undo != NULL); do { + page_t* undo_page = undo_block->page.frame; uint16_t offset = !rec ? trx_undo_page_report_insert( - undo_block, trx, index, clust_entry, &mtr, - bulk) + undo_block, undo_page, trx, index, clust_entry, + &mtr, bulk) : trx_undo_page_report_modify( - undo_block, trx, index, rec, offsets, update, + undo_block, undo_page, trx, index, + rec, offsets, update, cmpl_info, clust_entry, &mtr); if (UNIV_UNLIKELY(offset == 0)) { const uint16_t first_free = mach_read_from_2( TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->page.frame); - memset(undo_block->page.frame + first_free, 0, + + undo_page); + memset(undo_page + first_free, 0, (srv_page_size - FIL_PAGE_DATA_END) - first_free); diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 86f5b064b7fdb..3f904e3f252ea 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -54,12 +54,14 @@ static long long wsrep_seqno = -1; static unsigned char wsrep_uuid[16]; /** Write the WSREP XID information into rollback segment header. -@param[in,out] rseg_header rollback segment header -@param[in] xid WSREP XID -@param[in,out] mtr mini transaction */ +@param[in,out] rseg_header rollback segment header +@param[in,out] rseg_header_page rollback segment header page frame +@param[in] xid WSREP XID +@param[in,out] mtr mini-transaction */ static void trx_rseg_write_wsrep_checkpoint( buf_block_t* rseg_header, + page_t* rseg_header_page, const XID* xid, mtr_t* mtr) { @@ -69,42 +71,45 @@ trx_rseg_write_wsrep_checkpoint( mtr->write<4,mtr_t::MAYBE_NOP>(*rseg_header, TRX_RSEG + TRX_RSEG_WSREP_XID_FORMAT - + rseg_header->page.frame, + + rseg_header_page, uint32_t(xid->formatID)); mtr->write<4,mtr_t::MAYBE_NOP>(*rseg_header, TRX_RSEG + TRX_RSEG_WSREP_XID_GTRID_LEN - + rseg_header->page.frame, + + rseg_header_page, uint32_t(xid->gtrid_length)); mtr->write<4,mtr_t::MAYBE_NOP>(*rseg_header, TRX_RSEG + TRX_RSEG_WSREP_XID_BQUAL_LEN - + rseg_header->page.frame, + + rseg_header_page, uint32_t(xid->bqual_length)); const ulint xid_length = static_cast(xid->gtrid_length + xid->bqual_length); mtr->memcpy(*rseg_header, TRX_RSEG + TRX_RSEG_WSREP_XID_DATA - + rseg_header->page.frame, + + rseg_header_page, xid->data, xid_length); if (xid_length < XIDDATASIZE - && memcmp(TRX_RSEG + TRX_RSEG_WSREP_XID_DATA - + rseg_header->page.frame, field_ref_zero, + && memcmp(TRX_RSEG + TRX_RSEG_WSREP_XID_DATA + rseg_header_page, + field_ref_zero, XIDDATASIZE - xid_length)) { mtr->memset(rseg_header, - TRX_RSEG + TRX_RSEG_WSREP_XID_DATA + xid_length, + TRX_RSEG + TRX_RSEG_WSREP_XID_DATA + xid_length + + rseg_header_page, XIDDATASIZE - xid_length, 0); } } /** Update the WSREP XID information in rollback segment header. -@param[in,out] rseg_header rollback segment header -@param[in] xid WSREP XID -@param[in,out] mtr mini-transaction */ +@param[in,out] rseg_header rollback segment header +@param[in,out] rseg_header_page rollback segment header page frame +@param[in] xid WSREP XID +@param[in,out] mtr mini-transaction */ void trx_rseg_update_wsrep_checkpoint( buf_block_t* rseg_header, + page_t* rseg_header_page, const XID* xid, mtr_t* mtr) { @@ -123,7 +128,8 @@ trx_rseg_update_wsrep_checkpoint( } wsrep_seqno = xid_seqno; #endif /* UNIV_DEBUG */ - trx_rseg_write_wsrep_checkpoint(rseg_header, xid, mtr); + trx_rseg_write_wsrep_checkpoint(rseg_header, rseg_header_page, + xid, mtr); } static dberr_t trx_rseg_update_wsrep_checkpoint(const XID* xid, mtr_t* mtr) @@ -134,6 +140,8 @@ static dberr_t trx_rseg_update_wsrep_checkpoint(const XID* xid, mtr_t* mtr) if (UNIV_UNLIKELY(!rseg_header)) return err; + page_t *rseg_header_page= rseg_header->page.frame; + /* We must make check against wsrep_uuid here, the trx_rseg_update_wsrep_checkpoint() writes over wsrep_uuid with xid contents in debug mode and the memcmp() will never give nonzero @@ -142,10 +150,10 @@ static dberr_t trx_rseg_update_wsrep_checkpoint(const XID* xid, mtr_t* mtr) memcmp(wsrep_uuid, wsrep_xid_uuid(xid), sizeof wsrep_uuid); if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + - rseg_header->page.frame))) - trx_rseg_format_upgrade(rseg_header, mtr); + rseg_header_page))) + trx_rseg_format_upgrade(rseg_header, rseg_header_page, mtr); - trx_rseg_update_wsrep_checkpoint(rseg_header, xid, mtr); + trx_rseg_update_wsrep_checkpoint(rseg_header, rseg_header_page, xid, mtr); if (must_clear_rsegs) /* Because the UUID part of the WSREP XID differed from @@ -153,7 +161,8 @@ static dberr_t trx_rseg_update_wsrep_checkpoint(const XID* xid, mtr_t* mtr) reset the XID in all rollback segment headers. */ for (ulint rseg_id= 1; rseg_id < TRX_SYS_N_RSEGS; ++rseg_id) if (buf_block_t* block= trx_sys.rseg_array[rseg_id].get(mtr, &err)) - mtr->memset(block, TRX_RSEG + TRX_RSEG_WSREP_XID_INFO, + mtr->memset(block, + TRX_RSEG + TRX_RSEG_WSREP_XID_INFO + block->page.frame, TRX_RSEG_WSREP_XID_DATA + XIDDATASIZE - TRX_RSEG_WSREP_XID_INFO, 0); return err; @@ -179,11 +188,11 @@ void trx_rseg_update_wsrep_checkpoint(const XID* xid) @param[out] xid Transaction XID @return whether the WSREP XID was present */ static -bool trx_rseg_read_wsrep_checkpoint(const buf_block_t *rseg_header, XID &xid) +bool trx_rseg_read_wsrep_checkpoint(const page_t *rseg_header_page, XID &xid) { int formatID = static_cast( mach_read_from_4(TRX_RSEG + TRX_RSEG_WSREP_XID_FORMAT - + rseg_header->page.frame)); + + rseg_header_page)); if (formatID == 0) { return false; } @@ -191,14 +200,14 @@ bool trx_rseg_read_wsrep_checkpoint(const buf_block_t *rseg_header, XID &xid) xid.formatID = formatID; xid.gtrid_length = static_cast( mach_read_from_4(TRX_RSEG + TRX_RSEG_WSREP_XID_GTRID_LEN - + rseg_header->page.frame)); + + rseg_header_page)); xid.bqual_length = static_cast( mach_read_from_4(TRX_RSEG + TRX_RSEG_WSREP_XID_BQUAL_LEN - + rseg_header->page.frame)); + + rseg_header_page)); memcpy(xid.data, TRX_RSEG + TRX_RSEG_WSREP_XID_DATA - + rseg_header->page.frame, XIDDATASIZE); + + rseg_header_page, XIDDATASIZE); return true; } @@ -255,15 +264,16 @@ bool trx_rseg_read_wsrep_checkpoint(XID& xid) if (UNIV_UNLIKELY(!sys)) { continue; } + const page_t* sys_page = sys->page.frame; const uint32_t page_no = trx_sysf_rseg_get_page_no( - sys, rseg_id); + sys_page, rseg_id); if (page_no == FIL_NULL) { continue; } const buf_block_t* rseg_header = buf_page_get_gen( - page_id_t(trx_sysf_rseg_get_space(sys, rseg_id), + page_id_t(trx_sysf_rseg_get_space(sys_page, rseg_id), page_no), 0, RW_S_LATCH, nullptr, BUF_GET, &mtr); @@ -271,14 +281,16 @@ bool trx_rseg_read_wsrep_checkpoint(XID& xid) continue; } + const page_t* rseg_header_page = rseg_header->page.frame; + if (mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT - + rseg_header->page.frame)) { + + rseg_header_page)) { continue; } XID tmp_xid; long long tmp_seqno = 0; - if (trx_rseg_read_wsrep_checkpoint(rseg_header, tmp_xid) + if (trx_rseg_read_wsrep_checkpoint(rseg_header_page, tmp_xid) && (tmp_seqno = wsrep_xid_seqno(&tmp_xid)) > max_xid_seqno) { found = true; @@ -309,15 +321,20 @@ buf_block_t *trx_rseg_t::get(mtr_t *mtr, dberr_t *err) const return block; } +ATTRIBUTE_COLD /** Upgrade a rollback segment header page to MariaDB 10.3 format. -@param[in,out] rseg_header rollback segment header page -@param[in,out] mtr mini-transaction */ -void trx_rseg_format_upgrade(buf_block_t *rseg_header, mtr_t *mtr) +@param rseg_header rollback segment header page +@param rseg_header_page rollback segment header page frame +@param mtr mini-transaction */ +void trx_rseg_format_upgrade(buf_block_t *rseg_header, + page_t *rseg_header_page, mtr_t *mtr) { - mtr->memset(rseg_header, TRX_RSEG + TRX_RSEG_FORMAT, 4, 0); + mtr->memset(rseg_header, TRX_RSEG + TRX_RSEG_FORMAT + rseg_header_page, + 4, 0); /* Clear also possible garbage at the end of the page. Old InnoDB versions did not initialize unused parts of pages. */ - mtr->memset(rseg_header, TRX_RSEG + TRX_RSEG_MAX_TRX_ID + 8, + mtr->memset(rseg_header, TRX_RSEG + TRX_RSEG_MAX_TRX_ID + 8 + + rseg_header_page, srv_page_size - (FIL_PAGE_DATA_END + TRX_RSEG + TRX_RSEG_MAX_TRX_ID + 8), 0); @@ -340,22 +357,20 @@ buf_block_t *trx_rseg_header_create(fil_space_t *space, ulint rseg_id, fseg_create(space, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr, err); if (block) { - ut_ad(0 == mach_read_from_4(TRX_RSEG_FORMAT + TRX_RSEG + - block->page.frame)); - ut_ad(0 == mach_read_from_4(TRX_RSEG_HISTORY_SIZE + TRX_RSEG + - block->page.frame)); - ut_ad(0 == mach_read_from_4(TRX_RSEG_MAX_TRX_ID + TRX_RSEG + - block->page.frame)); + page_t *page= block->page.frame; + ut_ad(0 == mach_read_from_4(TRX_RSEG_FORMAT + TRX_RSEG + page)); + ut_ad(0 == mach_read_from_4(TRX_RSEG_HISTORY_SIZE + TRX_RSEG + page)); + ut_ad(0 == mach_read_from_4(TRX_RSEG_MAX_TRX_ID + TRX_RSEG + page)); /* Initialize the history list */ - flst_init(block, TRX_RSEG_HISTORY + TRX_RSEG, mtr); + flst_init(block, TRX_RSEG_HISTORY + TRX_RSEG + page, mtr); mtr->write<8,mtr_t::MAYBE_NOP>(*block, TRX_RSEG + TRX_RSEG_MAX_TRX_ID + - block->page.frame, max_trx_id); + page, max_trx_id); /* Reset the undo log slots */ - mtr->memset(block, TRX_RSEG_UNDO_SLOTS + TRX_RSEG, TRX_RSEG_N_SLOTS * 4, - 0xff); + mtr->memset(block, TRX_RSEG_UNDO_SLOTS + TRX_RSEG + page, + TRX_RSEG_N_SLOTS * 4, 0xff); } return block; } @@ -420,7 +435,7 @@ void trx_rseg_t::reinit(uint32_t page) @param[in] rseg_header rollback segment header @return error code */ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, - const buf_block_t *rseg_header) + const page_t *rseg_header) { ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN); @@ -461,17 +476,17 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr) &err); if (!rseg_hdr) return err; + const page_t *rseg_hdr_page= rseg_hdr->page.frame; - if (!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rseg_hdr->page.frame)) + if (!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rseg_hdr_page)) { trx_id_t id= mach_read_from_8(TRX_RSEG + TRX_RSEG_MAX_TRX_ID + - rseg_hdr->page.frame); + rseg_hdr_page); if (id > rseg->needs_purge) rseg->needs_purge= id; - const byte *binlog_name= - TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr->page.frame; + const byte *binlog_name= TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr_page; if (*binlog_name) { static_assert(TRX_RSEG_BINLOG_NAME_LEN == @@ -488,8 +503,7 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr) if (cmp >= 0) { uint64_t binlog_offset = - mach_read_from_8(TRX_RSEG + TRX_RSEG_BINLOG_OFFSET + - rseg_hdr->page.frame); + mach_read_from_8(TRX_RSEG + TRX_RSEG_BINLOG_OFFSET + rseg_hdr_page); if (cmp) { memcpy(trx_sys.recovered_binlog_filename, binlog_name, @@ -501,7 +515,8 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr) trx_sys.recovered_binlog_is_legacy_pos= false; } #ifdef WITH_WSREP - trx_rseg_read_wsrep_checkpoint(rseg_hdr, trx_sys.recovered_wsrep_xid); + trx_rseg_read_wsrep_checkpoint(rseg_hdr_page, + trx_sys.recovered_wsrep_xid); #endif } } @@ -515,16 +530,15 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr) /* Initialize the undo log lists according to the rseg header */ rseg->curr_size = mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE + - rseg_hdr->page.frame) + 1; - err= trx_undo_lists_init(rseg, rseg_hdr); + rseg_hdr_page) + 1; + err= trx_undo_lists_init(rseg, rseg_hdr_page); if (err != DB_SUCCESS); - else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY + - rseg_hdr->page.frame)) + else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY + rseg_hdr_page)) { rseg->history_size+= len; fil_addr_t node_addr= flst_get_last(TRX_RSEG + TRX_RSEG_HISTORY + - rseg_hdr->page.frame); + rseg_hdr_page); if (node_addr.page >= rseg->space->free_limit || node_addr.boffset < TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE || node_addr.boffset >= srv_page_size - TRX_UNDO_LOG_OLD_HDR_SIZE) @@ -540,17 +554,17 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr) if (!block) return err; - trx_id_t id= mach_read_from_8(block->page.frame + node_addr.boffset + - TRX_UNDO_TRX_ID); + const page_t *page= block->page.frame; + + trx_id_t id= mach_read_from_8(page + node_addr.boffset + TRX_UNDO_TRX_ID); if (id > rseg->needs_purge) rseg->needs_purge= id; - id= mach_read_from_8(block->page.frame + node_addr.boffset + - TRX_UNDO_TRX_NO); + id= mach_read_from_8(page + node_addr.boffset + TRX_UNDO_TRX_NO); if (id > rseg->needs_purge) rseg->needs_purge= id; rseg->set_last_commit(node_addr.boffset, id); - ut_ad(mach_read_from_2(block->page.frame + node_addr.boffset + + ut_ad(mach_read_from_2(page + node_addr.boffset + TRX_UNDO_NEEDS_PURGE) <= 1); if (rseg->last_page_no != FIL_NULL) @@ -610,14 +624,16 @@ dberr_t trx_rseg_array_init() for (ulint rseg_id = 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) { mtr.start(); if (const buf_block_t* sys = trx_sysf_get(&mtr, false)) { + const page_t* sys_page = sys->page.frame; + if (rseg_id == 0) { /* In case this is an upgrade from before MariaDB 10.3.5, fetch the base information from the TRX_SYS page. */ max_trx_id = mach_read_from_8( TRX_SYS + TRX_SYS_TRX_ID_STORE - + sys->page.frame); - trx_rseg_init_binlog_info(sys->page.frame); + + sys_page); + trx_rseg_init_binlog_info(sys_page); #ifdef WITH_WSREP if (trx_rseg_init_wsrep_xid( sys->page.frame, trx_sys.recovered_wsrep_xid)) { @@ -628,12 +644,12 @@ dberr_t trx_rseg_array_init() } const uint32_t page_no = trx_sysf_rseg_get_page_no( - sys, rseg_id); + sys_page, rseg_id); if (page_no != FIL_NULL) { trx_rseg_t& rseg = trx_sys.rseg_array[rseg_id]; rseg.init(fil_space_get( trx_sysf_rseg_get_space( - sys, rseg_id)), + sys_page, rseg_id)), page_no); ut_ad(rseg.is_persistent()); err = trx_rseg_mem_restore(&rseg, &mtr); @@ -688,8 +704,9 @@ dberr_t trx_rseg_array_init() } /* Finally, clear WSREP XID in TRX_SYS page. */ - mtr.memset(trx_sysf_get(&mtr), - TRX_SYS + TRX_SYS_WSREP_XID_INFO, + buf_block_t* sys = trx_sysf_get(&mtr); + mtr.memset(sys, TRX_SYS + TRX_SYS_WSREP_XID_INFO + + sys->page.frame, TRX_SYS_WSREP_XID_LEN, 0); mtr.commit(); } @@ -721,35 +738,3 @@ dberr_t trx_temp_rseg_create(mtr_t *mtr) } return DB_SUCCESS; } - -/** Update the offset information about the end of the binlog entry -which corresponds to the transaction just being committed. -In a replication slave, this updates the master binlog position -up to which replication has proceeded. -@param[in,out] rseg_header rollback segment header -@param[in] trx committing transaction -@param[in,out] mtr mini-transaction */ -void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, const trx_t *trx, - mtr_t *mtr) -{ - DBUG_LOG("trx", "trx_mysql_binlog_offset: " << trx->mysql_log_offset); - - const size_t len = strlen(trx->mysql_log_file_name) + 1; - - ut_ad(len > 1); - - if (UNIV_UNLIKELY(len > TRX_RSEG_BINLOG_NAME_LEN)) { - return; - } - - mtr->write<8,mtr_t::MAYBE_NOP>(*rseg_header, - TRX_RSEG + TRX_RSEG_BINLOG_OFFSET - + rseg_header->page.frame, - trx->mysql_log_offset); - - void* name = TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_header->page.frame; - - if (memcmp(trx->mysql_log_file_name, name, len)) { - mtr->memcpy(*rseg_header, name, trx->mysql_log_file_name, len); - } -} diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 33c408707cc34..622cf189afccf 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -68,8 +68,7 @@ trx_sys_print_mysql_binlog_offset() @param[in] sys_header @return an unallocated rollback segment slot in the TRX_SYS header @retval ULINT_UNDEFINED if not found */ -ulint -trx_sys_rseg_find_free(const buf_block_t* sys_header) +static ulint trx_sys_rseg_find_free(const page_t* sys_header) { for (ulint rseg_id = 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) { if (trx_sysf_rseg_get_page_no(sys_header, rseg_id) @@ -91,10 +90,11 @@ trx_sysf_get_n_rseg_slots() srv_available_undo_logs = 0; if (const buf_block_t* sys_header = trx_sysf_get(&mtr, false)) { + const page_t* sys_page = sys_header->page.frame; + for (ulint rseg_id = 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) { srv_available_undo_logs - += trx_sysf_rseg_get_page_no(sys_header, - rseg_id) + += trx_sysf_rseg_get_page_no(sys_page, rseg_id) != FIL_NULL; } } @@ -121,8 +121,9 @@ dberr_t trx_sys_create_sys_pages(mtr_t *mtr) } ut_a(block->page.id() == page_id_t(0, TRX_SYS_PAGE_NO)); - mtr->write<2>(*block, FIL_PAGE_TYPE + block->page.frame, - FIL_PAGE_TYPE_TRX_SYS); + page_t *page= block->page.frame; + + mtr->write<2>(*block, FIL_PAGE_TYPE + page, FIL_PAGE_TYPE_TRX_SYS); /* Reset the rollback segment slots. Old versions of InnoDB (before MySQL 5.5) define TRX_SYS_N_RSEGS as 256 and expect @@ -130,9 +131,9 @@ dberr_t trx_sys_create_sys_pages(mtr_t *mtr) static_assert(256 >= TRX_SYS_N_RSEGS, ""); static_assert(TRX_SYS + TRX_SYS_RSEGS + 256 * TRX_SYS_RSEG_SLOT_SIZE <= UNIV_PAGE_SIZE_MIN - FIL_PAGE_DATA_END, ""); - mtr->write<4>(*block, TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_PAGE_NO + - block->page.frame, FSP_FIRST_RSEG_PAGE_NO); - mtr->memset(block, TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_SLOT_SIZE, + mtr->write<4>(*block, TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_PAGE_NO + page, + FSP_FIRST_RSEG_PAGE_NO); + mtr->memset(block, TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_SLOT_SIZE + page, 255 * TRX_SYS_RSEG_SLOT_SIZE, 0xff); buf_block_t *r= trx_rseg_header_create(fil_system.sys_space, 0, 0, @@ -224,7 +225,8 @@ static trx_rseg_t *trx_rseg_create(ulint space_id) ut_ad(space->purpose == FIL_TYPE_TABLESPACE); if (buf_block_t *sys_header= trx_sysf_get(&mtr)) { - ulint rseg_id= trx_sys_rseg_find_free(sys_header); + page_t *sys_page= sys_header->page.frame; + ulint rseg_id= trx_sys_rseg_find_free(sys_page); dberr_t err; if (buf_block_t *rblock= rseg_id == ULINT_UNDEFINED ? nullptr : trx_rseg_header_create(space, rseg_id, 0, &mtr, &err)) @@ -234,12 +236,10 @@ static trx_rseg_t *trx_rseg_create(ulint space_id) ut_ad(rseg->is_persistent()); mtr.write<4,mtr_t::MAYBE_NOP> (*sys_header, TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_SPACE + - rseg_id * TRX_SYS_RSEG_SLOT_SIZE + sys_header->page.frame, - space_id); + rseg_id * TRX_SYS_RSEG_SLOT_SIZE + sys_page, space_id); mtr.write<4,mtr_t::MAYBE_NOP> (*sys_header, TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_PAGE_NO + - rseg_id * TRX_SYS_RSEG_SLOT_SIZE + sys_header->page.frame, - rseg->page_no); + rseg_id * TRX_SYS_RSEG_SLOT_SIZE + sys_page, rseg->page_no); } } } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a05ddbe901d83..a01aa432ad717 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -603,7 +603,7 @@ static dberr_t trx_resurrect_table_locks(trx_t *trx, const trx_undo_t &undo) trx_undo_rec_get_pars(undo_rec, &type, &cmpl_info, &updated_extern, &undo_no, &table_id); tables.emplace(table_id, type == TRX_UNDO_EMPTY); - undo_rec= trx_undo_get_prev_rec(block, page_offset(undo_rec), + undo_rec= trx_undo_get_prev_rec(block, undo_rec, undo.hdr_page_no, undo.hdr_offset, true, &mtr); } @@ -990,21 +990,22 @@ void trx_t::commit_empty(mtr_t *mtr) buf_page_get(page_id_t(rseg->space->id, undo->hdr_page_no), 0, RW_X_LATCH, mtr)) { + page_t *upage= u->page.frame; ut_d(const uint16_t state= - mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + u->page.frame)); + mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + upage)); ut_ad(state == undo->state || state == TRX_UNDO_ACTIVE); static_assert(TRX_UNDO_PAGE_START + 2 == TRX_UNDO_PAGE_FREE, "compatibility"); - ut_ad(!memcmp(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + u->page.frame, - TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + u->page.frame, 2)); + ut_ad(!memcmp(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + upage, + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + upage, 2)); ut_ad(mach_read_from_4(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_PREV + - FIL_ADDR_PAGE + u->page.frame) == FIL_NULL); + FIL_ADDR_PAGE + upage) == FIL_NULL); ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_PREV + - FIL_ADDR_BYTE + u->page.frame) == 0); + FIL_ADDR_BYTE + upage) == 0); ut_ad(!memcmp(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_PREV + - u->page.frame, + upage, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_NEXT + - u->page.frame, FIL_ADDR_SIZE)); + upage, FIL_ADDR_SIZE)); /* Delete the last undo log header, which must be for this transaction. @@ -1017,7 +1018,7 @@ void trx_t::commit_empty(mtr_t *mtr) If we simply changed the undo page state to TRX_UNDO_CACHED, then trx_undo_reuse_cached() could run out of space. We will release the space consumed by our empty undo log to avoid that. */ - for (byte *last= &u->page.frame[TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE], + for (byte *last= &upage[TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE], *prev= nullptr;;) { /* TRX_UNDO_PREV_LOG is only being read in debug assertions, and @@ -1030,31 +1031,31 @@ void trx_t::commit_empty(mtr_t *mtr) if (uint16_t next= mach_read_from_2(TRX_UNDO_NEXT_LOG + last)) { ut_ad(ulint{next} + TRX_UNDO_LOG_XA_HDR_SIZE < srv_page_size - 100); - ut_ad(&u->page.frame[next] > last); + ut_ad(&upage[next] > last); ut_ad(mach_read_from_2(TRX_UNDO_LOG_START + last) <= next); prev= last; - last= &u->page.frame[next]; + last= &upage[next]; continue; } ut_ad(mach_read_from_8(TRX_UNDO_TRX_ID + last) == id); ut_ad(!mach_read_from_8(TRX_UNDO_TRX_NO + last)); - ut_ad(!memcmp(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + u->page.frame, + ut_ad(!memcmp(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + upage, TRX_UNDO_LOG_START + last, 2)); if (prev) { mtr->memcpy(*u, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + - u->page.frame, prev + TRX_UNDO_LOG_START, 2); - const ulint free= page_offset(last); + upage, prev + TRX_UNDO_LOG_START, 2); + const ulint free= last - upage; mtr->write<2>(*u, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + - u->page.frame, free); - mtr->write<2>(*u, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + u->page.frame, + upage, free); + mtr->write<2>(*u, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + upage, TRX_UNDO_CACHED); - mtr->write<2>(*u, TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG + u->page.frame, - page_offset(prev)); + mtr->write<2>(*u, TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG + upage, + prev - upage); mtr->write<2>(*u, prev + TRX_UNDO_NEXT_LOG, 0U); - mtr->memset(u, free, srv_page_size - FIL_PAGE_DATA_END - free, 0); + mtr->memset(u, last, srv_page_size - FIL_PAGE_DATA_END - free, 0); /* We may have updated PAGE_MAX_TRX_ID on secondary index pages to this->id. Ensure that trx_sys.m_max_trx_id will be recovered @@ -1069,14 +1070,15 @@ void trx_t::commit_empty(mtr_t *mtr) if (mach_read_from_8(prev + TRX_UNDO_TRX_NO) >= id); else if (buf_block_t *rseg_header= rseg->get(mtr, nullptr)) { - byte *m= TRX_RSEG + TRX_RSEG_MAX_TRX_ID + rseg_header->page.frame; + page_t *rseg_page= rseg_header->page.frame; + byte *m= TRX_RSEG + TRX_RSEG_MAX_TRX_ID + rseg_page; do { if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + - rseg_header->page.frame))) + rseg_page))) /* This must have been upgraded from before MariaDB 10.3.5. */ - trx_rseg_format_upgrade(rseg_header, mtr); + trx_rseg_format_upgrade(rseg_header, rseg_page, mtr); else if (mach_read_from_8(m) >= id) continue; mtr->write<8>(*rseg_header, m, id); @@ -1093,7 +1095,7 @@ void trx_t::commit_empty(mtr_t *mtr) trx_undo_mem_create_at_db_start(). This page will remain available to trx_undo_reuse_cached(), and it will eventually be freed by trx_purge_truncate_rseg_history(). */ - mtr->write<2>(*u, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + u->page.frame, + mtr->write<2>(*u, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + upage, TRX_UNDO_CACHED); break; } diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index c0f5b1fb22cc7..1bad847469501 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -116,10 +116,10 @@ trx_undo_mem_create( @return start offset */ static uint16_t trx_undo_page_get_start(const buf_block_t *block, uint32_t page_no, - uint16_t offset) + const byte *offset) { return page_no == block->page.id().page_no() - ? mach_read_from_2(offset + TRX_UNDO_LOG_START + block->page.frame) + ? mach_read_from_2(offset + TRX_UNDO_LOG_START) : TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE; } @@ -131,7 +131,7 @@ uint16_t trx_undo_page_get_start(const buf_block_t *block, uint32_t page_no, @retval nullptr if none exists */ trx_undo_rec_t* trx_undo_page_get_first_rec(const buf_block_t *block, uint32_t page_no, - uint16_t offset) + const byte *offset) { uint16_t start= trx_undo_page_get_start(block, page_no, offset); uint16_t end= trx_undo_page_get_end(block, page_no, offset); @@ -148,27 +148,28 @@ trx_undo_page_get_first_rec(const buf_block_t *block, uint32_t page_no, static trx_undo_rec_t* trx_undo_page_get_last_rec(const buf_block_t *block, uint32_t page_no, - uint16_t offset) + const byte *offset) { uint16_t start= trx_undo_page_get_start(block, page_no, offset); uint16_t end= trx_undo_page_get_end(block, page_no, offset); ut_ad(start <= end); - return start >= end - ? nullptr - : block->page.frame + mach_read_from_2(block->page.frame + end - 2); + if (start >= end) + return nullptr; + page_t *page= block->page.frame; + return page + mach_read_from_2(page + end - 2); } /** Get the previous record in an undo log from the previous page. @param[in,out] block undo log page -@param[in] rec undo record offset in the page @param[in] page_no undo log header page number @param[in] offset undo log header offset on page @param[in] shared latching mode: true=RW_S_LATCH, false=RW_X_LATCH @param[in,out] mtr mini-transaction @return undo log record, the page latched, NULL if none */ static trx_undo_rec_t* -trx_undo_get_prev_rec_from_prev_page(buf_block_t *&block, uint16_t rec, - uint32_t page_no, uint16_t offset, +trx_undo_get_prev_rec_from_prev_page(buf_block_t *&block, + uint32_t page_no, + uint16_t offset, bool shared, mtr_t *mtr) { uint32_t prev_page_no= mach_read_from_4(TRX_UNDO_PAGE_HDR + @@ -186,7 +187,8 @@ trx_undo_get_prev_rec_from_prev_page(buf_block_t *&block, uint16_t rec, if (!buf_page_make_young_if_needed(&block->page)) buf_read_ahead_linear(block->page.id(), 0, false); - return trx_undo_page_get_last_rec(block, page_no, offset); + return trx_undo_page_get_last_rec(block, page_no, + block->page.frame + offset); } /** Get the previous undo log record. @@ -198,37 +200,37 @@ trx_undo_get_prev_rec_from_prev_page(buf_block_t *&block, uint16_t rec, @retval NULL if none */ static trx_undo_rec_t* -trx_undo_page_get_prev_rec(const buf_block_t *block, trx_undo_rec_t *rec, +trx_undo_page_get_prev_rec(const buf_block_t *block, const trx_undo_rec_t *rec, uint32_t page_no, uint16_t offset) { - ut_ad(block->page.frame == page_align(rec)); + const page_t *page= block->page.frame; + ut_ad(page == page_align(rec)); return - rec == block->page.frame + trx_undo_page_get_start(block, page_no, offset) + rec == page + trx_undo_page_get_start(block, page_no, page + offset) ? nullptr - : block->page.frame + mach_read_from_2(rec - 2); + : const_cast(page) + mach_read_from_2(rec - 2); } /** Get the previous record in an undo log. @param[in,out] block undo log page -@param[in] rec undo record offset in the page +@param[in] rec undo record in the page @param[in] page_no undo log header page number @param[in] offset undo log header offset on page @param[in] shared latching mode: true=RW_S_LATCH, false=RW_X_LATCH @param[in,out] mtr mini-transaction @return undo log record, the page latched, NULL if none */ trx_undo_rec_t* -trx_undo_get_prev_rec(buf_block_t *&block, uint16_t rec, uint32_t page_no, +trx_undo_get_prev_rec(buf_block_t *&block, const byte *rec, uint32_t page_no, uint16_t offset, bool shared, mtr_t *mtr) { - if (trx_undo_rec_t *prev= trx_undo_page_get_prev_rec(block, - block->page.frame + rec, + if (trx_undo_rec_t *prev= trx_undo_page_get_prev_rec(block, rec, page_no, offset)) return prev; /* We have to go to the previous undo log page to look for the previous record */ - return trx_undo_get_prev_rec_from_prev_page(block, rec, page_no, offset, + return trx_undo_get_prev_rec_from_prev_page(block, page_no, offset, shared, mtr); } @@ -257,7 +259,9 @@ trx_undo_get_next_rec_from_next_page(const buf_block_t *&block, block= buf_page_get_gen(page_id_t(block->page.id().space(), next), 0, mode, nullptr, BUF_GET_POSSIBLY_FREED, mtr); - return block ? trx_undo_page_get_first_rec(block, page_no, offset) : nullptr; + return block + ? trx_undo_page_get_first_rec(block, page_no, block->page.frame + offset) + : nullptr; } /** Get the first record in an undo log. @@ -278,17 +282,18 @@ trx_undo_get_first_rec(const fil_space_t &space, uint32_t page_no, buf_block_t *b= buf_page_get_gen(page_id_t{space.id, page_no}, 0, mode, nullptr, BUF_GET, mtr, err); block= b; - if (!block) + if (!b) return nullptr; if (!buf_page_make_young_if_needed(&b->page)) buf_read_ahead_linear(b->page.id(), 0, false); - if (trx_undo_rec_t *rec= trx_undo_page_get_first_rec(b, page_no, offset)) + if (trx_undo_rec_t *rec= + trx_undo_page_get_first_rec(b, page_no, b->page.frame + offset)) return rec; - return trx_undo_get_next_rec_from_next_page(block, page_no, offset, mode, - mtr); + return trx_undo_get_next_rec_from_next_page(block, page_no, offset, + mode, mtr); } inline void UndorecApplier::apply_undo_rec(const trx_undo_rec_t *rec) @@ -361,12 +366,13 @@ ATTRIBUTE_COLD void trx_t::apply_log() return; } + const page_t *page= block->page.frame; UndorecApplier log_applier(page_id, id); for (;;) { trx_undo_rec_t *rec= trx_undo_page_get_first_rec(block, page_id.page_no(), - undo->hdr_offset); + page + undo->hdr_offset); while (rec) { block->page.fix(); @@ -376,13 +382,12 @@ ATTRIBUTE_COLD void trx_t::apply_log() log_applier.apply_undo_rec(rec); mtr.start(); mtr.page_lock(block, RW_S_LATCH); - rec= trx_undo_page_get_next_rec(block, page_offset(rec), - page_id.page_no(), undo->hdr_offset); + rec= trx_undo_page_get_next_rec(block, rec, page_id.page_no(), + undo->hdr_offset); } uint32_t next= mach_read_from_4(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + - FLST_NEXT + FIL_ADDR_PAGE + - block->page.frame); + FLST_NEXT + FIL_ADDR_PAGE + page); if (next == FIL_NULL) break; next_page_id.set_page_no(next); @@ -391,6 +396,7 @@ ATTRIBUTE_COLD void trx_t::apply_log() block= buf_page_get_gen(next_page_id, 0, RW_S_LATCH, block, BUF_GET, &mtr); if (UNIV_UNLIKELY(!block)) break; + page= block->page.frame; log_applier.assign_next(next_page_id); } mtr.commit(); @@ -402,34 +408,32 @@ ATTRIBUTE_COLD void trx_t::apply_log() /** Initialize an undo log page. NOTE: This corresponds to a redo log record and must not be changed! @see mtr_t::undo_create() -@param block undo log page */ -void trx_undo_page_init(const buf_block_t &block) +@param block undo log page +@param page undo log page frame */ +void trx_undo_page_init(const buf_block_t &block, page_t *page) { - mach_write_to_2(my_assume_aligned<2>(FIL_PAGE_TYPE + block.page.frame), + mach_write_to_2(my_assume_aligned<2>(FIL_PAGE_TYPE + page), FIL_PAGE_UNDO_LOG); static_assert(TRX_UNDO_PAGE_HDR == FIL_PAGE_DATA, "compatibility"); - memset_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + block.page.frame, - 0, 2); + memset_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + page, 0, 2); mach_write_to_2(my_assume_aligned<2> - (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + block.page.frame), + (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + page), TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); - memcpy_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + block.page.frame, - TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + block.page.frame, - 2); + memcpy_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + page, + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + page, 2); /* The following corresponds to flst_zero_both(), but without writing log. */ memset_aligned<4>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_PREV + - FIL_ADDR_PAGE + block.page.frame, 0xff, 4); + FIL_ADDR_PAGE + page, 0xff, 4); memset_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_PREV + - FIL_ADDR_BYTE + block.page.frame, 0, 2); + FIL_ADDR_BYTE + page, 0, 2); memset_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_NEXT + - FIL_ADDR_PAGE + block.page.frame, 0xff, 4); + FIL_ADDR_PAGE + page, 0xff, 4); memset_aligned<2>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + FLST_NEXT + - FIL_ADDR_BYTE + block.page.frame, 0, 2); + FIL_ADDR_BYTE + page, 0, 2); static_assert(TRX_UNDO_PAGE_NODE + FLST_NEXT + FIL_ADDR_BYTE + 2 == TRX_UNDO_PAGE_HDR_SIZE, "compatibility"); /* Preserve TRX_UNDO_SEG_HDR, but clear the rest of the page. */ - memset_aligned<2>(TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE + - block.page.frame, 0, + memset_aligned<2>(TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE + page, 0, srv_page_size - (TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE + FIL_PAGE_DATA_END)); } @@ -438,7 +442,7 @@ void trx_undo_page_init(const buf_block_t &block) @param rseg_header rollback segment header @return slot index @retval ULINT_UNDEFINED if not found */ -static ulint trx_rsegf_undo_find_free(const buf_block_t *rseg_header) +static ulint trx_rsegf_undo_find_free(const page_t *rseg_header) { ulint max_slots= TRX_RSEG_N_SLOTS; @@ -457,6 +461,7 @@ static ulint trx_rsegf_undo_find_free(const buf_block_t *rseg_header) /** Create an undo log segment. @param[in,out] space tablespace @param[in,out] rseg_hdr rollback segment header (x-latched) +@param[in,out] rseg_hdr_page rollback segment header page frame @param[out] id undo slot number @param[out] err error code @param[in,out] mtr mini-transaction @@ -464,13 +469,14 @@ static ulint trx_rsegf_undo_find_free(const buf_block_t *rseg_header) @retval NULL on failure */ static MY_ATTRIBUTE((nonnull, warn_unused_result)) buf_block_t* -trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id, +trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, + page_t *rseg_hdr_page, ulint *id, dberr_t *err, mtr_t *mtr) { buf_block_t* block; uint32_t n_reserved; - const ulint slot_no = trx_rsegf_undo_find_free(rseg_hdr); + const ulint slot_no = trx_rsegf_undo_find_free(rseg_hdr_page); if (slot_no == ULINT_UNDEFINED) { ib::warn() << "Cannot find a free slot for an undo log. Do" @@ -498,26 +504,28 @@ trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id, return block; } + page_t* page = block->page.frame; + mtr->undo_create(*block); - trx_undo_page_init(*block); + trx_undo_page_init(*block, page); - mtr->write<2>(*block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + block->page.frame, + mtr->write<2>(*block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + page, TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE); mtr->write<2,mtr_t::MAYBE_NOP>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG - + block->page.frame, 0U); + + page, 0U); - flst_init(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST - + block->page.frame, mtr); + flst_init(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + page, mtr); - *err = flst_add_last(block, TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST, - block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, + *err = flst_add_last(block, + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + page, + block, + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + page, space->free_limit, mtr); *id = slot_no; mtr->write<4>(*rseg_hdr, TRX_RSEG + TRX_RSEG_UNDO_SLOTS - + slot_no * TRX_RSEG_SLOT_SIZE + rseg_hdr->page.frame, + + slot_no * TRX_RSEG_SLOT_SIZE + rseg_hdr_page, block->page.id().page_no()); *err = DB_SUCCESS; @@ -526,20 +534,21 @@ trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id, /** Initialize an undo log header. @param[in,out] undo_page undo log segment header page +@param[in,out] upage undo log segment header page frame @param[in] trx_id transaction identifier @param[in,out] mtr mini-transaction @return header byte offset on page */ -static uint16_t trx_undo_header_create(buf_block_t *undo_page, trx_id_t trx_id, - mtr_t* mtr) +static uint16_t trx_undo_header_create(buf_block_t *undo_page, page_t *upage, + trx_id_t trx_id, mtr_t* mtr) { /* Reset the TRX_UNDO_PAGE_TYPE in case this page is being repurposed after upgrading to MariaDB 10.3. */ byte *undo_type= my_assume_aligned<2> - (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + undo_page->page.frame); + (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + upage); ut_ad(mach_read_from_2(undo_type) <= 2); mtr->write<2,mtr_t::MAYBE_NOP>(*undo_page, undo_type, 0U); byte *start= my_assume_aligned<4>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + - undo_page->page.frame); + upage); const uint16_t free= mach_read_from_2(start + 2); static_assert(TRX_UNDO_PAGE_START + 2 == TRX_UNDO_PAGE_FREE, "compatibility"); @@ -553,7 +562,7 @@ static uint16_t trx_undo_header_create(buf_block_t *undo_page, trx_id_t trx_id, mtr->memset(*undo_page, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START, 4, start, 2); uint16_t prev_log= mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG + - undo_page->page.frame); + upage); ut_ad(prev_log < free); alignas(4) byte buf[4]; mach_write_to_2(buf, TRX_UNDO_ACTIVE); @@ -562,15 +571,13 @@ static uint16_t trx_undo_header_create(buf_block_t *undo_page, trx_id_t trx_id, static_assert(!((TRX_UNDO_SEG_HDR + TRX_UNDO_STATE) % 4), "alignment"); mtr->memcpy (*undo_page, my_assume_aligned<4> - (TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + undo_page->page.frame), buf, 4); + (TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + upage), buf, 4); if (prev_log) - mtr->write<2>(*undo_page, prev_log + TRX_UNDO_NEXT_LOG + - undo_page->page.frame, free); + mtr->write<2>(*undo_page, prev_log + TRX_UNDO_NEXT_LOG + upage, free); mtr->write<8,mtr_t::MAYBE_NOP>(*undo_page, free + TRX_UNDO_TRX_ID + - undo_page->page.frame, trx_id); - if (UNIV_UNLIKELY(mach_read_from_8(free + TRX_UNDO_TRX_NO + - undo_page->page.frame) != 0)) - mtr->memset(undo_page, free + TRX_UNDO_TRX_NO, 8, 0); + upage, trx_id); + if (UNIV_UNLIKELY(mach_read_from_8(free + TRX_UNDO_TRX_NO + upage) != 0)) + mtr->memset(undo_page, free + TRX_UNDO_TRX_NO + upage, 8, 0); /* Write TRX_UNDO_NEEDS_PURGE=1 and TRX_UNDO_LOG_START. */ mach_write_to_2(buf, 1); @@ -578,32 +585,33 @@ static uint16_t trx_undo_header_create(buf_block_t *undo_page, trx_id_t trx_id, static_assert(TRX_UNDO_NEEDS_PURGE + 2 == TRX_UNDO_LOG_START, "compatibility"); mtr->memcpy(*undo_page, free + TRX_UNDO_NEEDS_PURGE + - undo_page->page.frame, buf, 4); + upage, buf, 4); /* Initialize all fields TRX_UNDO_XID_EXISTS to TRX_UNDO_HISTORY_NODE. */ if (prev_log) { - mtr->memset(undo_page, free + TRX_UNDO_XID_EXISTS, + mtr->memset(undo_page, free + TRX_UNDO_XID_EXISTS + upage, TRX_UNDO_PREV_LOG - TRX_UNDO_XID_EXISTS, 0); mtr->write<2,mtr_t::MAYBE_NOP>(*undo_page, free + TRX_UNDO_PREV_LOG + - undo_page->page.frame, prev_log); + upage, prev_log); static_assert(TRX_UNDO_PREV_LOG + 2 == TRX_UNDO_HISTORY_NODE, "compatibility"); - mtr->memset(undo_page, free + TRX_UNDO_HISTORY_NODE, FLST_NODE_SIZE, 0); + mtr->memset(undo_page, free + TRX_UNDO_HISTORY_NODE + upage, + FLST_NODE_SIZE, 0); static_assert(TRX_UNDO_LOG_OLD_HDR_SIZE == TRX_UNDO_HISTORY_NODE + FLST_NODE_SIZE, "compatibility"); } else - mtr->memset(undo_page, free + TRX_UNDO_XID_EXISTS, + mtr->memset(undo_page, free + TRX_UNDO_XID_EXISTS + upage, TRX_UNDO_LOG_OLD_HDR_SIZE - TRX_UNDO_XID_EXISTS, 0); return free; } /** Write X/Open XA Transaction Identifier (XID) to undo log header @param[in,out] block undo header page -@param[in] offset undo header record offset +@param[in] log_hdr undo header record offset @param[in] xid distributed transaction identifier @param[in,out] mtr mini-transaction */ -static void trx_undo_write_xid(buf_block_t *block, uint16_t offset, +static void trx_undo_write_xid(buf_block_t *block, trx_ulogf_t *log_hdr, const XID &xid, mtr_t *mtr) { DBUG_ASSERT(xid.gtrid_length > 0); @@ -613,9 +621,7 @@ static void trx_undo_write_xid(buf_block_t *block, uint16_t offset, static_assert(MAXGTRIDSIZE + MAXBQUALSIZE == XIDDATASIZE, "gtrid and bqual don't fit xid data"); DBUG_ASSERT(mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG + - block->page.frame) == offset); - - trx_ulogf_t* log_hdr= block->page.frame + offset; + page_align(log_hdr)) == page_offset(log_hdr)); mtr->write<4,mtr_t::MAYBE_NOP>(*block, log_hdr + TRX_UNDO_XA_FORMAT, static_cast(xid.formatID)); @@ -625,11 +631,10 @@ static void trx_undo_write_xid(buf_block_t *block, uint16_t offset, static_cast(xid.bqual_length)); const ulint xid_length= static_cast(xid.gtrid_length + xid.bqual_length); - mtr->memcpy(*block, - &block->page.frame[offset + TRX_UNDO_XA_XID], + mtr->memcpy(*block, log_hdr + TRX_UNDO_XA_XID, xid.data, xid_length); if (UNIV_LIKELY(xid_length < XIDDATASIZE)) - mtr->memset(block, offset + TRX_UNDO_XA_XID + xid_length, + mtr->memset(block, log_hdr + TRX_UNDO_XA_XID + xid_length, XIDDATASIZE - xid_length, 0); } @@ -660,6 +665,7 @@ trx_undo_read_xid(const trx_ulogf_t* log_hdr, XID* xid) buf_block_t *trx_undo_add_page(trx_undo_t *undo, mtr_t *mtr, dberr_t *err) { buf_block_t *new_block= nullptr; + page_t *new_page; uint32_t n_reserved; /* When we add a page to an undo log, this is analogous to @@ -669,11 +675,13 @@ buf_block_t *trx_undo_add_page(trx_undo_t *undo, mtr_t *mtr, dberr_t *err) trx_rseg_t *rseg= undo->rseg; rseg->latch.wr_lock(SRW_LOCK_CALL); + page_t *header_page; buf_block_t *header_block= buf_page_get_gen(page_id_t{rseg->space->id, undo->hdr_page_no}, 0, RW_X_LATCH, nullptr, BUF_GET, mtr, err); if (!header_block) goto func_exit; + buf_page_make_young_if_needed(&header_block->page); *err= fsp_reserve_free_extents(&n_reserved, rseg->space, 1, FSP_UNDO, mtr); @@ -681,9 +689,11 @@ buf_block_t *trx_undo_add_page(trx_undo_t *undo, mtr_t *mtr, dberr_t *err) if (UNIV_UNLIKELY(*err != DB_SUCCESS)) goto func_exit; + header_page= header_block->page.frame; + new_block= fseg_alloc_free_page_general(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + - header_block->page.frame, + header_page, undo->top_page_no + 1, FSP_UP, true, mtr, mtr, err); rseg->space->release_free_extents(n_reserved); @@ -694,10 +704,12 @@ buf_block_t *trx_undo_add_page(trx_undo_t *undo, mtr_t *mtr, dberr_t *err) undo->last_page_no= new_block->page.id().page_no(); mtr->undo_create(*new_block); - trx_undo_page_init(*new_block); - *err= flst_add_last(header_block, TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST, - new_block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, - rseg->space->free_limit, mtr); + new_page= new_block->page.frame; + trx_undo_page_init(*new_block, new_page); + *err= flst_add_last(header_block, + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + header_page, + new_block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + + new_page, rseg->space->free_limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) new_block= nullptr; else @@ -749,9 +761,13 @@ trx_undo_free_page( buf_page_make_young_if_needed(&header_block->page); const uint32_t limit = rseg->space->free_limit; + page_t* undo_page = undo_block->page.frame; + page_t* header_page = header_block->page.frame; - *err = flst_remove(header_block, TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST, - undo_block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, + *err = flst_remove(header_block, + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + header_page, + undo_block, + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + undo_page, limit, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) { @@ -759,8 +775,7 @@ trx_undo_free_page( } const fil_addr_t last_addr = flst_get_last( - TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST - + header_block->page.frame); + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + header_page); if (UNIV_UNLIKELY(last_addr.page == page_no) || UNIV_UNLIKELY(last_addr.page != FIL_NULL && last_addr.page >= limit) @@ -773,7 +788,7 @@ trx_undo_free_page( } *err = fseg_free_page(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER - + header_block->page.frame, + + header_page, rseg->space, page_no, mtr); if (UNIV_UNLIKELY(*err != DB_SUCCESS)) { return FIL_NULL; @@ -835,15 +850,18 @@ static dberr_t trx_undo_truncate_end(trx_undo_t &undo, undo_no_t limit, trx_undo_rec_t *trunc_here= nullptr; undo.rseg->latch.wr_lock(SRW_LOCK_CALL); dberr_t err; + page_t *undo_page= nullptr; buf_block_t *undo_block= buf_page_get_gen(page_id_t{undo.rseg->space->id, undo.last_page_no}, 0, RW_X_LATCH, nullptr, BUF_GET, &mtr, &err); if (UNIV_UNLIKELY(!undo_block)) goto func_exit; + undo_page= undo_block->page.frame; + for (trx_undo_rec_t *rec= - trx_undo_page_get_last_rec(undo_block, - undo.hdr_page_no, undo.hdr_offset); + trx_undo_page_get_last_rec(undo_block, undo.hdr_page_no, + undo_page + undo.hdr_offset); rec; ) { if (trx_undo_rec_get_undo_no(rec) < limit) @@ -869,8 +887,7 @@ static dberr_t trx_undo_truncate_end(trx_undo_t &undo, undo_no_t limit, if (trunc_here && err == DB_SUCCESS) mtr.write<2>(*undo_block, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + - undo_block->page.frame, - ulint(trunc_here - undo_block->page.frame)); + undo_page, ulint(trunc_here - undo_page)); mtr.commit(); return err; @@ -939,7 +956,8 @@ trx_undo_truncate_start( } last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no, - hdr_offset); + hdr_offset + + undo_page->page.frame); if (trx_undo_rec_get_undo_no(last_rec) >= limit) { goto done; } @@ -1107,10 +1125,11 @@ trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no) goto corrupted_undo; } + const page_t* last_page = last->page.frame; + if (const trx_undo_rec_t* rec = trx_undo_page_get_last_rec( - last, page_no, offset)) { - undo->top_offset = static_cast( - rec - last->page.frame); + last, page_no, last_page + offset)) { + undo->top_offset = static_cast(rec - last_page); undo->top_undo_no = trx_undo_rec_get_undo_no(rec); ut_ad(!undo->empty()); } else { @@ -1218,18 +1237,22 @@ trx_undo_create(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo, { ulint id; buf_block_t* block = rseg->get(mtr, err); + page_t* page; if (block) { - block = trx_undo_seg_create(rseg->space, block, &id, err, mtr); + page = block->page.frame; + block = trx_undo_seg_create(rseg->space, block, page, + &id, err, mtr); } if (!block) { return NULL; } + page = block->page.frame; rseg->curr_size++; - uint16_t offset = trx_undo_header_create(block, trx->id, mtr); + uint16_t offset = trx_undo_header_create(block, page, trx->id, mtr); *undo = trx_undo_mem_create(rseg, id, trx->id, &trx->xid, block->page.id().page_no(), offset); @@ -1243,11 +1266,9 @@ trx_undo_create(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo, if (trx->dict_operation) { (*undo)->dict_operation = true; - mtr->write<1,mtr_t::MAYBE_NOP>(*block, - block->page.frame + offset + mtr->write<1,mtr_t::MAYBE_NOP>(*block, page + offset + TRX_UNDO_DICT_TRANS, 1U); - mtr->write<8,mtr_t::MAYBE_NOP>(*block, - block->page.frame + offset + mtr->write<8,mtr_t::MAYBE_NOP>(*block, page + offset + TRX_UNDO_TABLE_ID, 0U); } @@ -1303,21 +1324,21 @@ trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo, buf_page_make_young_if_needed(&block->page); + page_t* page = block->page.frame; + UT_LIST_REMOVE(rseg->undo_cached, undo); *pundo = undo; - uint16_t offset = trx_undo_header_create(block, trx->id, mtr); + uint16_t offset = trx_undo_header_create(block, page, trx->id, mtr); trx_undo_mem_init_for_reuse(undo, trx->id, &trx->xid, offset); if (trx->dict_operation) { undo->dict_operation = TRUE; - mtr->write<1,mtr_t::MAYBE_NOP>(*block, - block->page.frame + offset + mtr->write<1,mtr_t::MAYBE_NOP>(*block, page + offset + TRX_UNDO_DICT_TRANS, 1U); - mtr->write<8,mtr_t::MAYBE_NOP>(*block, - block->page.frame + offset + mtr->write<8,mtr_t::MAYBE_NOP>(*block, page + offset + TRX_UNDO_TABLE_ID, 0U); } @@ -1466,10 +1487,12 @@ void trx_undo_set_state_at_prepare(trx_t *trx, trx_undo_t *undo, bool rollback, return; } + page_t* page = block->page.frame; + if (rollback) { ut_ad(undo->state == TRX_UNDO_PREPARED); - mtr->write<2>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE - + block->page.frame, TRX_UNDO_ACTIVE); + mtr->write<2>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + page, + TRX_UNDO_ACTIVE); return; } @@ -1479,14 +1502,13 @@ void trx_undo_set_state_at_prepare(trx_t *trx, trx_undo_t *undo, bool rollback, undo->xid = trx->xid; /*------------------------------*/ - mtr->write<2>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE - + block->page.frame, undo->state); - uint16_t offset = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG - + block->page.frame); - mtr->write<1>(*block, block->page.frame + offset + TRX_UNDO_XID_EXISTS, - 1U); + mtr->write<2>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + page, + undo->state); + byte *log_hdr = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG + + page) + page; + mtr->write<1>(*block, log_hdr + TRX_UNDO_XID_EXISTS, 1U); - trx_undo_write_xid(block, offset, undo->xid, mtr); + trx_undo_write_xid(block, log_hdr, undo->xid, mtr); } /** At shutdown, frees the undo logs of a transaction. */