diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-10-11 08:41:36 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-10-11 08:41:36 +0300 |
commit | d04f2de80a96b3ff9290ee27507195bfb01fc77f (patch) | |
tree | 49da698fbe99c5888f41238b0cda4e1eedebf2e2 /storage/innobase/btr | |
parent | 5e17b1f7cbfc256850ed139a0a4898040e16ff60 (diff) | |
parent | b05be3ef8c8668ddbcbe8e1c08dcd4fcc88eb4cf (diff) | |
download | mariadb-git-d04f2de80a96b3ff9290ee27507195bfb01fc77f.tar.gz |
Merge 10.4 into 10.5
Diffstat (limited to 'storage/innobase/btr')
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 227 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 20 |
2 files changed, 101 insertions, 146 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index e36f675221d..f1d899691d9 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -2091,104 +2091,92 @@ btr_root_raise_and_insert( } } -/*************************************************************//** -Decides if the page should be split at the convergence point of inserts +/** Decide if the page should be split at the convergence point of inserts converging to the left. -@return TRUE if split recommended */ -ibool -btr_page_get_split_rec_to_left( -/*===========================*/ - btr_cur_t* cursor, /*!< in: cursor at which to insert */ - rec_t** split_rec) /*!< out: if split recommended, - the first record on upper half page, - or NULL if tuple to be inserted should - be first */ +@param[in] cursor insert position +@return the first record to be moved to the right half page +@retval NULL if no split is recommended */ +rec_t* btr_page_get_split_rec_to_left(const btr_cur_t* cursor) { - page_t* page; - rec_t* insert_point; - rec_t* infimum; - - page = btr_cur_get_page(cursor); - insert_point = btr_cur_get_rec(cursor); + rec_t* split_rec = btr_cur_get_rec(cursor); + const page_t* page = page_align(split_rec); if (page_header_get_ptr(page, PAGE_LAST_INSERT) - == page_rec_get_next(insert_point)) { - - infimum = page_get_infimum_rec(page); + != page_rec_get_next(split_rec)) { + return NULL; + } - /* 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. */ + /* 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() + would already hold when row_ins_clust_index_entry_low() + is being invoked to insert the the metadata record. + So, we can only assert that when the metadata record exists, + 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)), + cursor->index->table->not_redundant()) + & REC_INFO_MIN_REC_FLAG)); - if (infimum != insert_point - && page_rec_get_next(infimum) != insert_point) { + const rec_t* infimum = page_get_infimum_rec(page); - *split_rec = insert_point; - } else { - *split_rec = page_rec_get_next(insert_point); - } + /* 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. */ - return(TRUE); + if (split_rec == infimum + || split_rec == page_rec_get_next_const(infimum)) { + split_rec = page_rec_get_next(split_rec); } - return(FALSE); + return split_rec; } -/*************************************************************//** -Decides if the page should be split at the convergence point of inserts +/** Decide if the page should be split at the convergence point of inserts converging to the right. -@return TRUE if split recommended */ -ibool -btr_page_get_split_rec_to_right( -/*============================*/ - btr_cur_t* cursor, /*!< in: cursor at which to insert */ - rec_t** split_rec) /*!< out: if split recommended, - the first record on upper half page, - or NULL if tuple to be inserted should - be first */ +@param[in] cursor insert position +@param[out] split_rec if split recommended, the first record + on the right half page, or + NULL if the to-be-inserted record + should be first +@return whether split is recommended */ +bool +btr_page_get_split_rec_to_right(const btr_cur_t* cursor, rec_t** split_rec) { - page_t* page; - rec_t* insert_point; - - page = btr_cur_get_page(cursor); - insert_point = btr_cur_get_rec(cursor); + rec_t* insert_point = btr_cur_get_rec(cursor); + const page_t* page = page_align(insert_point); /* 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 pattern of sequential inserts here. */ - if (page_header_get_ptr(page, PAGE_LAST_INSERT) == insert_point) { - - rec_t* next_rec; - - next_rec = page_rec_get_next(insert_point); - - if (page_rec_is_supremum(next_rec)) { -split_at_new: - /* Split at the new record to insert */ - *split_rec = NULL; - } else { - rec_t* next_next_rec = page_rec_get_next(next_rec); - if (page_rec_is_supremum(next_next_rec)) { - - goto split_at_new; - } + if (page_header_get_ptr(page, PAGE_LAST_INSERT) != insert_point) { + return false; + } - /* If there are >= 2 user records up from the insert - point, split all but 1 off. We want to keep one because - then sequential inserts can use the adaptive hash - index, as they can do the necessary checks of the right - search position just by looking at the records on this - page. */ + insert_point = page_rec_get_next(insert_point); - *split_rec = next_next_rec; + if (page_rec_is_supremum(insert_point)) { + insert_point = NULL; + } else { + insert_point = page_rec_get_next(insert_point); + if (page_rec_is_supremum(insert_point)) { + insert_point = NULL; } - return(TRUE); + /* If there are >= 2 user records up from the insert + point, split all but 1 off. We want to keep one because + then sequential inserts can use the adaptive hash + index, as they can do the necessary checks of the right + search position just by looking at the records on this + page. */ } - return(FALSE); + *split_rec = insert_point; + return true; } /*************************************************************//** @@ -2836,30 +2824,20 @@ btr_page_split_and_insert( buf_block_t* block; page_t* page; page_zip_des_t* page_zip; - ulint page_no; - byte direction; - ulint hint_page_no; 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; buf_block_t* right_block; - buf_block_t* insert_block; page_cur_t* page_cursor; rec_t* first_rec; byte* buf = 0; /* remove warning */ rec_t* move_limit; - ibool insert_will_fit; - ibool insert_left; ulint n_iterations = 0; - rec_t* rec; ulint n_uniq; - dict_index_t* index; - - index = btr_cur_get_index(cursor); - if (dict_index_is_spatial(index)) { + if (cursor->index->is_spatial()) { /* Split rtree page and update parent */ return(rtr_page_split_and_insert(flags, cursor, offsets, heap, tuple, n_ext, mtr)); @@ -2890,23 +2868,19 @@ func_start: ut_ad(!page_is_empty(page)); /* try to insert to the next page if possible before split */ - rec = btr_insert_into_right_sibling( - flags, cursor, offsets, *heap, tuple, n_ext, mtr); - - if (rec != NULL) { + if (rec_t* rec = btr_insert_into_right_sibling( + flags, cursor, offsets, *heap, tuple, n_ext, mtr)) { return(rec); } - page_no = block->page.id.page_no(); - /* 1. Decide the split record; split_rec == NULL means that the tuple to be inserted should be the first record on the upper half-page */ - insert_left = FALSE; + bool insert_left = false; + ulint hint_page_no = block->page.id.page_no() + 1; + byte direction = FSP_UP; - if (tuple != NULL && n_iterations > 0) { - direction = FSP_UP; - hint_page_no = page_no + 1; + if (tuple && n_iterations > 0) { split_rec = btr_page_get_split_rec(cursor, tuple, n_ext); if (split_rec == NULL) { @@ -2914,17 +2888,10 @@ func_start: cursor, tuple, offsets, n_uniq, heap); } } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) { - direction = FSP_UP; - hint_page_no = page_no + 1; - - } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) { + } else if ((split_rec = btr_page_get_split_rec_to_left(cursor))) { direction = FSP_DOWN; - hint_page_no = page_no - 1; - ut_ad(split_rec); + hint_page_no -= 2; } else { - direction = FSP_UP; - hint_page_no = page_no + 1; - /* If there is only one record in the index page, we can't split the node in the middle by default. We need to determine whether the new record will be inserted @@ -2949,7 +2916,7 @@ func_start: new_block = btr_page_alloc(cursor->index, hint_page_no, direction, btr_page_get_level(page), mtr, mtr); - if (new_block == NULL && os_has_said_disk_full) { + if (!new_block) { return(NULL); } @@ -2974,12 +2941,8 @@ func_start: *offsets = rec_get_offsets(split_rec, cursor->index, *offsets, page_is_leaf(page), n_uniq, heap); - if (tuple != NULL) { - insert_left = cmp_dtuple_rec( - tuple, split_rec, *offsets) < 0; - } else { - insert_left = 1; - } + insert_left = !tuple + || cmp_dtuple_rec(tuple, split_rec, *offsets) < 0; if (!insert_left && new_page_zip && n_iterations > 0) { /* If a compressed page has already been split, @@ -3014,10 +2977,10 @@ insert_empty: on the appropriate half-page, we may release the tree x-latch. We can then move the records after releasing the tree latch, thus reducing the tree latch contention. */ + bool insert_will_fit; if (tuple == NULL) { - insert_will_fit = 1; - } - else if (split_rec) { + insert_will_fit = true; + } else if (split_rec) { insert_will_fit = !new_page_zip && btr_page_insert_fits(cursor, split_rec, offsets, tuple, n_ext, heap); @@ -3114,8 +3077,6 @@ insert_empty: /* Update the lock table and possible hash index. */ lock_move_rec_list_end(new_block, block, move_limit); - ut_ad(!dict_index_is_spatial(index)); - btr_search_move_or_delete_hash_entries( new_block, block); @@ -3147,18 +3108,15 @@ insert_empty: /* 6. The split and the tree modification is now completed. Decide the page where the tuple should be inserted */ + rec_t* rec; + buf_block_t* const insert_block = insert_left + ? left_block : right_block; - if (tuple == NULL) { + if (UNIV_UNLIKELY(!tuple)) { rec = NULL; goto func_exit; } - if (insert_left) { - insert_block = left_block; - } else { - insert_block = right_block; - } - /* 7. Reposition the cursor for insert and try insertion */ page_cursor = btr_cur_get_page_cur(cursor); @@ -3235,9 +3193,7 @@ func_exit: ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index)); ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index)); - if (tuple == NULL) { - ut_ad(rec == NULL); - } + ut_ad(tuple || !rec); ut_ad(!rec || rec_offs_validate(rec, cursor->index, *offsets)); return(rec); } @@ -3342,25 +3298,22 @@ btr_parse_set_min_rec_mark( return(ptr + 2); } -/****************************************************************//** -Sets a record as the predefined minimum record. */ -void -btr_set_min_rec_mark( -/*=================*/ - rec_t* rec, /*!< in: record */ - mtr_t* mtr) /*!< in: mtr */ +/** Sets a record as the predefined minimum record. */ +void btr_set_min_rec_mark(rec_t* rec, mtr_t* mtr) { - ulint info_bits; + const bool comp = page_rec_is_comp(rec); - if (page_rec_is_comp(rec)) { - info_bits = rec_get_info_bits(rec, TRUE); + ut_ad(rec == page_rec_get_next_const(page_get_infimum_rec( + page_align(rec)))); + ut_ad(!(rec_get_info_bits(page_rec_get_next(rec), comp) + & REC_INFO_MIN_REC_FLAG)); + size_t info_bits = rec_get_info_bits(rec, comp); + if (comp) { rec_set_info_bits_new(rec, info_bits | REC_INFO_MIN_REC_FLAG); btr_set_min_rec_mark_log(rec, MLOG_COMP_REC_MIN_MARK, mtr); } else { - info_bits = rec_get_info_bits(rec, FALSE); - rec_set_info_bits_old(rec, info_bits | REC_INFO_MIN_REC_FLAG); btr_set_min_rec_mark_log(rec, MLOG_REC_MIN_MARK, mtr); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index bb032b0a7e8..8140eea96e1 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3437,7 +3437,7 @@ fail_err: && page_get_n_recs(page) >= 2 && dict_index_get_space_reserve() + rec_size > max_size && (btr_page_get_split_rec_to_right(cursor, &dummy) - || btr_page_get_split_rec_to_left(cursor, &dummy))) { + || btr_page_get_split_rec_to_left(cursor))) { goto fail; } @@ -5888,6 +5888,9 @@ btr_cur_pessimistic_delete( #endif /* UNIV_ZIP_DEBUG */ } + rec_t* next_rec = NULL; + bool min_mark_next_rec = false; + if (page_is_leaf(page)) { const bool is_metadata = rec_is_metadata( rec, page_rec_is_comp(rec)); @@ -5965,20 +5968,14 @@ discard_page: goto return_after_reservations; } - rec_t* next_rec = page_rec_get_next(rec); + next_rec = page_rec_get_next(rec); if (!page_has_prev(page)) { - /* If we delete the leftmost node pointer on a non-leaf level, we must mark the new leftmost node pointer as the predefined minimum record */ - /* This will make page_zip_validate() fail until - page_cur_delete_rec() completes. This is harmless, - because everything will take place within a single - mini-transaction and because writing to the redo log - is an atomic operation (performed by mtr_commit()). */ - btr_set_min_rec_mark(next_rec, mtr); + min_mark_next_rec = true; } else if (dict_index_is_spatial(index)) { /* For rtree, if delete the leftmost node pointer, we need to update parent page. */ @@ -6046,6 +6043,11 @@ discard_page: block->zip_size(), mtr); page_cur_delete_rec(btr_cur_get_page_cur(cursor), index, offsets, mtr); + + if (min_mark_next_rec) { + btr_set_min_rec_mark(next_rec, mtr); + } + #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ |