Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 124 additions & 95 deletions storage/innobase/btr/btr0btr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -908,26 +908,31 @@ btr_page_get_father_block(
mtr_t* mtr, /*!< in: mtr */
btr_cur_t* cursor) /*!< out: cursor on node pointer record,
its page x-latched */
noexcept
{
rec_t *rec=
page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame));
const page_t *page= btr_cur_get_page(cursor);
const rec_t *rec= page_is_comp(page)
? page_rec_next_get<true>(page, page + PAGE_NEW_INFIMUM)
: page_rec_next_get<false>(page, page + PAGE_OLD_INFIMUM);
if (UNIV_UNLIKELY(!rec))
return nullptr;
cursor->page_cur.rec= rec;
cursor->page_cur.rec= const_cast<rec_t*>(rec);
return btr_page_get_parent(offsets, heap, cursor, mtr);
}

/** Seek to the parent page of a B-tree page.
@param[in,out] mtr mini-transaction
@param[in,out] cursor cursor pointing to the x-latched parent page
@param mtr mini-transaction
@param cursor cursor pointing to the x-latched parent page
@return whether the cursor was successfully positioned */
bool btr_page_get_father(mtr_t* mtr, btr_cur_t* cursor)
bool btr_page_get_father(mtr_t *mtr, btr_cur_t *cursor) noexcept
{
rec_t *rec=
page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame));
page_t *page= btr_cur_get_page(cursor);
const rec_t *rec= page_is_comp(page)
? page_rec_next_get<true>(page, page + PAGE_NEW_INFIMUM)
: page_rec_next_get<false>(page, page + PAGE_OLD_INFIMUM);
if (UNIV_UNLIKELY(!rec))
return false;
cursor->page_cur.rec= rec;
cursor->page_cur.rec= const_cast<rec_t*>(rec);
mem_heap_t *heap= mem_heap_create(100);
const bool got= btr_page_get_parent(nullptr, heap, cursor, mtr);
mem_heap_free(heap);
Expand Down Expand Up @@ -957,8 +962,7 @@ static void btr_free_root(buf_block_t *block, const fil_space_t &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(block, PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr));
}
}

Expand Down Expand Up @@ -1164,8 +1168,8 @@ btr_free_but_not_root(
/* NOTE: page hash indexes are dropped when a page is freed inside
fsp0fsp. */

bool finished = fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_LEAF
+ block->page.frame, &mtr
bool finished = fseg_free_step(block, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
&mtr
#ifdef BTR_CUR_HASH_ADAPT
, ahi
#endif /* BTR_CUR_HASH_ADAPT */
Expand All @@ -1183,8 +1187,9 @@ btr_free_but_not_root(

finished = !btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP,
*block, *space)
|| fseg_free_step_not_header(PAGE_HEADER + PAGE_BTR_SEG_TOP
+ block->page.frame, &mtr
|| fseg_free_step_not_header(block,
PAGE_HEADER + PAGE_BTR_SEG_TOP,
&mtr
#ifdef BTR_CUR_HASH_ADAPT
,ahi
#endif /* BTR_CUR_HASH_ADAPT */
Expand Down Expand Up @@ -1925,7 +1930,6 @@ btr_root_raise_and_insert(
dberr_t* err) /*!< out: error code */
{
dict_index_t* index;
rec_t* rec;
dtuple_t* node_ptr;
ulint level;
rec_t* node_ptr_rec;
Expand Down Expand Up @@ -2082,7 +2086,13 @@ 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));
const rec_t* rec= page_is_comp(new_block->page.frame)
? page_rec_next_get<true>(new_block->page.frame,
new_block->page.frame
+ PAGE_NEW_INFIMUM)
: page_rec_next_get<false>(new_block->page.frame,
new_block->page.frame
+ PAGE_OLD_INFIMUM);
ut_ad(rec); /* We just created the page. */

/* Build the node pointer (= node key and page address) for the
Expand Down Expand Up @@ -2157,90 +2167,109 @@ btr_root_raise_and_insert(

/** Decide if the page should be split at the convergence point of inserts
converging to the left.
@param[in] cursor insert position
@param 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)
@retval nullptr if no split is recommended */
rec_t *btr_page_get_split_rec_to_left(const btr_cur_t *cursor) noexcept
{
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(split_rec)) {
return NULL;
}

/* 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));
const rec_t *split_rec= btr_cur_get_rec(cursor);
const page_t *page= btr_cur_get_page(cursor);
const rec_t *const last= page + page_header_get_offs(page, PAGE_LAST_INSERT);

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);
}
if (page_is_comp(page))
{
if (last != page_rec_next_get<true>(page, split_rec))
return nullptr;
/* 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. */
const rec_t *const infimum= page + PAGE_NEW_INFIMUM;
ut_ad(!page_is_leaf(page) || page_has_prev(page) ||
cursor->index()->is_instant() ||
!(rec_get_info_bits(page_rec_next_get<true>(page, infimum), true) &
REC_INFO_MIN_REC_FLAG));
/* 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_next_get<true>(page, infimum))
split_rec= page_rec_next_get<true>(page, split_rec);
}
else
{
if (last != page_rec_next_get<false>(page, split_rec))
return nullptr;
const rec_t *const infimum= page + PAGE_OLD_INFIMUM;
ut_ad(!page_is_leaf(page) || page_has_prev(page) ||
cursor->index()->is_instant() ||
!(rec_get_info_bits(page_rec_next_get<false>(page, infimum), false) &
REC_INFO_MIN_REC_FLAG));
if (split_rec == infimum ||
split_rec == page_rec_next_get<false>(page, infimum))
split_rec= page_rec_next_get<false>(page, split_rec);
}

return split_rec;
return const_cast<rec_t*>(split_rec);
}

/** Decide if the page should be split at the convergence point of inserts
converging to the right.
@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
@param cursor insert position
@param split_rec if split recommended, the first record on the right
half page, or nullptr 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)
btr_page_get_split_rec_to_right(const btr_cur_t *cursor, rec_t **split_rec)
noexcept
{
rec_t* insert_point = btr_cur_get_rec(cursor);
const page_t* page = page_align(insert_point);
const rec_t *insert_point= btr_cur_get_rec(cursor);
const 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
pattern of sequential inserts here. */

if (page_header_get_ptr(page, PAGE_LAST_INSERT) != insert_point) {
return false;
}

insert_point = page_rec_get_next(insert_point);

if (!insert_point || 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;
}
/* 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 + page_header_get_offs(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. */
}
if (page_is_comp(page))
{
const rec_t *const supremum= page + PAGE_NEW_SUPREMUM;
insert_point= page_rec_next_get<true>(page, insert_point);
if (!insert_point);
else if (insert_point == supremum)
insert_point= nullptr;
else
{
insert_point= page_rec_next_get<true>(page, insert_point);
if (insert_point == supremum)
insert_point= nullptr;
/* 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 do the necessary checks of the right search position
just by looking at the records on this page. */
}
}
else
{
const rec_t *const supremum= page + PAGE_OLD_SUPREMUM;
insert_point= page_rec_next_get<false>(page, insert_point);
if (!insert_point);
else if (insert_point == supremum)
insert_point= nullptr;
else
{
insert_point= page_rec_next_get<false>(page, insert_point);
if (insert_point == supremum)
insert_point= nullptr;
}
}

*split_rec = insert_point;
return true;
*split_rec= const_cast<rec_t*>(insert_point);
return true;
}

/*************************************************************//**
Expand Down Expand Up @@ -4695,31 +4724,31 @@ 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 rec_t* rec, /*!< in: index record */
const page_cur_t& cur, /*!< in: cursor to 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 */
noexcept
{
ulint len;
const page_t* page;
const rec_t* rec = page_cur_get_rec(&cur);
const page_t* page = cur.block->page.frame;
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(index->n_core_fields);

if (index->is_ibuf()) {
Expand Down Expand Up @@ -4900,7 +4929,7 @@ btr_index_page_validate(
return true;
}

if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
if (!btr_index_rec_validate(cur, index, TRUE)) {
break;
}

Expand Down
Loading