mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
MDEV-21098: Assertion failure in rec_get_offsets_func()
The function rec_get_offsets_func() used to hit ut_error due to an invalid rec_get_status() value of a ROW_FORMAT!=REDUNDANT record. This fix is twofold: We will not only avoid a crash on corruption in this case, but we will also make more effort to validate each record every time we are iterating over index page records. rec_get_offsets_func(): Do not crash on a corrupted record. page_rec_get_nth(): Return nullptr on error. page_dir_slot_get_rec_validate(): Like page_dir_slot_get_rec(), but validate the pointer and return nullptr on error. page_cur_search_with_match(), page_cur_search_with_match_bytes(), page_dir_split_slot(), page_cur_move_to_next(): Indicate failure in a return value. page_cur_search(): Replaced with page_cur_search_with_match(). rec_get_next_ptr_const(), rec_get_next_ptr(): Replaced with page_rec_get_next_low(). TODO: rtr_page_split_initialize_nodes(), rtr_update_mbr_field(), and possibly other SPATIAL INDEX functions fail to properly handle errors. Reviewed by: Thirunarayanan Balathandayuthapani Tested by: Matthias Leich Performance tested by: Axel Schwenke
This commit is contained in:
parent
a6f7c8edc9
commit
63478e72de
29 changed files with 1269 additions and 1058 deletions
|
@ -760,6 +760,9 @@ btr_page_get_father_block(
|
|||
rec_t* rec
|
||||
= page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
|
||||
block)));
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return nullptr;
|
||||
}
|
||||
btr_cur_position(index, rec, block, cursor);
|
||||
return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr));
|
||||
}
|
||||
|
@ -777,6 +780,9 @@ bool btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
|
|||
rec_t* rec
|
||||
= page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
|
||||
block)));
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return false;
|
||||
}
|
||||
btr_cur_position(index, rec, block, cursor);
|
||||
|
||||
heap = mem_heap_create(100);
|
||||
|
@ -1252,16 +1258,19 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
|
|||
ut_ad(index->is_dummy || block->page.id().page_no() != index->page ||
|
||||
!page_has_siblings(block->page.frame));
|
||||
|
||||
/* Save the cursor position. */
|
||||
const ulint pos= page_rec_get_n_recs_before(cursor->rec);
|
||||
|
||||
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
|
||||
return DB_CORRUPTION;
|
||||
|
||||
btr_search_drop_page_hash_index(block);
|
||||
|
||||
buf_block_t *old= buf_block_alloc();
|
||||
/* Copy the old page to temporary space */
|
||||
memcpy_aligned<UNIV_PAGE_SIZE_MIN>(old->page.frame, block->page.frame,
|
||||
srv_page_size);
|
||||
|
||||
btr_search_drop_page_hash_index(block);
|
||||
|
||||
/* Save the cursor position. */
|
||||
const ulint pos= page_rec_get_n_recs_before(cursor->rec);
|
||||
|
||||
page_create(block, mtr, index->table->not_redundant());
|
||||
if (index->is_spatial())
|
||||
block->page.frame[FIL_PAGE_TYPE + 1]= byte(FIL_PAGE_RTREE);
|
||||
|
@ -1315,10 +1324,10 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
|
|||
}
|
||||
|
||||
/* Restore the cursor position. */
|
||||
if (pos)
|
||||
cursor->rec = page_rec_get_nth(block->page.frame, pos);
|
||||
else
|
||||
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)))
|
||||
return DB_CORRUPTION;
|
||||
|
||||
mtr->set_log_mode(log_mode);
|
||||
|
||||
|
@ -1543,13 +1552,16 @@ btr_page_reorganize(
|
|||
return btr_page_reorganize_low(cursor, index, mtr);
|
||||
|
||||
ulint pos= page_rec_get_n_recs_before(cursor->rec);
|
||||
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
|
||||
return DB_CORRUPTION;
|
||||
|
||||
dberr_t err= page_zip_reorganize(cursor->block, index, page_zip_level, mtr,
|
||||
true);
|
||||
if (err == DB_FAIL);
|
||||
else if (pos)
|
||||
cursor->rec= page_rec_get_nth(cursor->block->page.frame, pos);
|
||||
else
|
||||
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)))
|
||||
err= DB_CORRUPTION;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -1745,7 +1757,6 @@ btr_root_raise_and_insert(
|
|||
dberr_t* err) /*!< out: error code */
|
||||
{
|
||||
dict_index_t* index;
|
||||
ulint new_page_no;
|
||||
rec_t* rec;
|
||||
dtuple_t* node_ptr;
|
||||
ulint level;
|
||||
|
@ -1907,8 +1918,9 @@ btr_root_raise_and_insert(
|
|||
*heap = mem_heap_create(1000);
|
||||
}
|
||||
|
||||
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));
|
||||
new_page_no = new_block->page.id().page_no();
|
||||
ut_ad(rec); /* We just created the page. */
|
||||
|
||||
/* Build the node pointer (= node key and page address) for the
|
||||
child */
|
||||
|
@ -1961,9 +1973,20 @@ btr_root_raise_and_insert(
|
|||
ibuf_reset_free_bits(new_block);
|
||||
}
|
||||
|
||||
if (tuple != NULL) {
|
||||
if (tuple) {
|
||||
ut_ad(dtuple_check_typed(tuple));
|
||||
/* Reposition the cursor to the child node */
|
||||
page_cur_search(new_block, index, tuple, page_cursor);
|
||||
ulint low_match = 0, up_match = 0;
|
||||
|
||||
if (page_cur_search_with_match(new_block, index, tuple,
|
||||
PAGE_CUR_LE,
|
||||
&up_match, &low_match,
|
||||
page_cursor, nullptr)) {
|
||||
if (err) {
|
||||
*err = DB_CORRUPTION;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* Set cursor to first record on child node */
|
||||
page_cur_set_before_first(new_block, page_cursor);
|
||||
|
@ -2042,7 +2065,7 @@ btr_page_get_split_rec_to_right(const btr_cur_t* cursor, rec_t** split_rec)
|
|||
|
||||
insert_point = page_rec_get_next(insert_point);
|
||||
|
||||
if (page_rec_is_supremum(insert_point)) {
|
||||
if (!insert_point || page_rec_is_supremum(insert_point)) {
|
||||
insert_point = NULL;
|
||||
} else {
|
||||
insert_point = page_rec_get_next(insert_point);
|
||||
|
@ -2230,19 +2253,19 @@ btr_page_insert_fits(
|
|||
end_rec) will end up on the other half page from tuple when it is
|
||||
inserted. */
|
||||
|
||||
if (split_rec == NULL) {
|
||||
rec = page_rec_get_next(page_get_infimum_rec(page));
|
||||
if (!(end_rec = split_rec)) {
|
||||
end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
|
||||
|
||||
} else if (cmp_dtuple_rec(tuple, split_rec, *offsets) >= 0) {
|
||||
|
||||
rec = page_rec_get_next(page_get_infimum_rec(page));
|
||||
end_rec = split_rec;
|
||||
} else {
|
||||
} 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)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
got_rec:
|
||||
if (total_data + page_dir_calc_reserved_space(total_n_recs)
|
||||
<= free_space) {
|
||||
|
||||
|
@ -2274,7 +2297,9 @@ btr_page_insert_fits(
|
|||
return(true);
|
||||
}
|
||||
|
||||
rec = page_rec_get_next_const(rec);
|
||||
if (!(rec = page_rec_get_next_const(rec))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(false);
|
||||
|
@ -2511,8 +2536,10 @@ btr_page_tuple_smaller(
|
|||
/* Read the first user record in the page. */
|
||||
block = btr_cur_get_block(cursor);
|
||||
page_cur_set_before_first(block, &pcur);
|
||||
page_cur_move_to_next(&pcur);
|
||||
first_rec = page_cur_get_rec(&pcur);
|
||||
if (UNIV_UNLIKELY(!(first_rec = page_cur_move_to_next(&pcur)))) {
|
||||
ut_ad("corrupted page" == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
*offsets = rec_get_offsets(first_rec, cursor->index, *offsets,
|
||||
page_is_leaf(block->page.frame)
|
||||
|
@ -2554,6 +2581,7 @@ btr_insert_into_right_sibling(
|
|||
MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK));
|
||||
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
|
||||
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)))) {
|
||||
|
@ -2581,9 +2609,13 @@ btr_insert_into_right_sibling(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
page_cur_search(
|
||||
next_block, cursor->index, tuple, PAGE_CUR_LE,
|
||||
&next_page_cursor);
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
if (page_cur_search_with_match(next_block, cursor->index, tuple,
|
||||
PAGE_CUR_LE, &up_match, &low_match,
|
||||
&next_page_cursor, nullptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
max_size = page_get_max_insert_size_after_reorganize(next_page, 1);
|
||||
|
||||
|
@ -2788,6 +2820,7 @@ btr_page_split_and_insert(
|
|||
ulint n_uniq;
|
||||
|
||||
ut_ad(*err == DB_SUCCESS);
|
||||
ut_ad(dtuple_check_typed(tuple));
|
||||
|
||||
if (cursor->index->is_spatial()) {
|
||||
/* Split rtree page and update parent */
|
||||
|
@ -2855,9 +2888,16 @@ func_start:
|
|||
page_get_infimum_rec(page));
|
||||
} else {
|
||||
split_rec = NULL;
|
||||
goto got_split_rec;
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(!split_rec)) {
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
got_split_rec:
|
||||
/* 2. Allocate a new page to the index */
|
||||
const uint16_t page_level = btr_page_get_level(page);
|
||||
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
|
||||
|
@ -2906,9 +2946,17 @@ func_start:
|
|||
goto insert_empty;
|
||||
}
|
||||
} else if (insert_left) {
|
||||
ut_a(n_iterations > 0);
|
||||
if (UNIV_UNLIKELY(!n_iterations)) {
|
||||
corrupted:
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
first_rec = page_rec_get_next(page_get_infimum_rec(page));
|
||||
insert_move_limit:
|
||||
move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
|
||||
if (UNIV_UNLIKELY(!first_rec || !move_limit)) {
|
||||
goto corrupted;
|
||||
}
|
||||
} else {
|
||||
insert_empty:
|
||||
ut_ad(!split_rec);
|
||||
|
@ -2919,7 +2967,7 @@ insert_empty:
|
|||
|
||||
first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
|
||||
tuple, n_ext);
|
||||
move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
|
||||
goto insert_move_limit;
|
||||
}
|
||||
|
||||
/* 4. Do first the modifications in the tree structure */
|
||||
|
@ -3086,7 +3134,14 @@ insert_empty:
|
|||
/* 7. Reposition the cursor for insert and try insertion */
|
||||
page_cursor = btr_cur_get_page_cur(cursor);
|
||||
|
||||
page_cur_search(insert_block, cursor->index, tuple, page_cursor);
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
if (page_cur_search_with_match(insert_block, cursor->index, tuple,
|
||||
PAGE_CUR_LE, &up_match, &low_match,
|
||||
page_cursor, nullptr)) {
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
|
||||
offsets, heap, n_ext, mtr);
|
||||
|
@ -3440,8 +3495,8 @@ btr_compress(
|
|||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
dict_index_t* index;
|
||||
buf_block_t* merge_block;
|
||||
page_t* merge_page = NULL;
|
||||
buf_block_t* merge_block = nullptr;
|
||||
page_t* merge_page = nullptr;
|
||||
page_zip_des_t* merge_page_zip;
|
||||
ibool is_left;
|
||||
buf_block_t* block;
|
||||
|
@ -3499,7 +3554,10 @@ btr_compress(
|
|||
|
||||
if (adjust) {
|
||||
nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor));
|
||||
ut_ad(nth_rec > 0);
|
||||
if (UNIV_UNLIKELY(!nth_rec || nth_rec == ULINT_UNDEFINED)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (left_page_no == FIL_NULL && right_page_no == FIL_NULL) {
|
||||
|
@ -3648,7 +3706,12 @@ cannot_merge:
|
|||
}
|
||||
|
||||
if (adjust) {
|
||||
nth_rec += page_rec_get_n_recs_before(orig_pred);
|
||||
ulint n = page_rec_get_n_recs_before(orig_pred);
|
||||
if (UNIV_UNLIKELY(!n || n == ULINT_UNDEFINED)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
nth_rec += n;
|
||||
}
|
||||
} else {
|
||||
rec_t* orig_succ;
|
||||
|
@ -3866,16 +3929,20 @@ cannot_merge:
|
|||
ut_ad(leftmost_child
|
||||
|| btr_check_node_ptr(index, merge_block, mtr));
|
||||
func_exit:
|
||||
MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
|
||||
|
||||
if (adjust) {
|
||||
ut_ad(nth_rec > 0);
|
||||
btr_cur_position(
|
||||
index,
|
||||
page_rec_get_nth(merge_block->page.frame,
|
||||
nth_rec),
|
||||
merge_block, cursor);
|
||||
}
|
||||
if (rec_t* nth
|
||||
= page_rec_get_nth(merge_block->page.frame,
|
||||
nth_rec)) {
|
||||
btr_cur_position(index, nth,
|
||||
merge_block, cursor);
|
||||
} else {
|
||||
err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
|
||||
MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
|
||||
} else {
|
||||
err_exit:
|
||||
/* We play it safe and reset the free bits. */
|
||||
|
@ -3912,6 +3979,9 @@ btr_discard_only_page_on_level(
|
|||
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));
|
||||
/* 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);
|
||||
ut_ad(rec_is_metadata(r, *index) == index->is_instant());
|
||||
|
||||
while (block->page.id().page_no() != dict_index_get_page(index)) {
|
||||
|
@ -4083,14 +4153,17 @@ btr_discard_page(
|
|||
|
||||
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)) {
|
||||
rec_t* node_ptr = page_rec_get_next(
|
||||
page_get_infimum_rec(merge_block->page.frame));
|
||||
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));
|
||||
/* We have to mark the leftmost node pointer as the
|
||||
predefined minimum record. */
|
||||
btr_set_min_rec_mark<true>(node_ptr, *merge_block,
|
||||
mtr);
|
||||
} else {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
} else {
|
||||
btr_discard_only_page_on_level(index, block, mtr);
|
||||
|
@ -4550,16 +4623,15 @@ next_field:
|
|||
/************************************************************//**
|
||||
Checks the size and number of fields in records based on the definition of
|
||||
the index.
|
||||
@return TRUE if ok */
|
||||
@return true if ok */
|
||||
static
|
||||
ibool
|
||||
bool
|
||||
btr_index_page_validate(
|
||||
/*====================*/
|
||||
buf_block_t* block, /*!< in: index page */
|
||||
dict_index_t* index) /*!< in: index */
|
||||
{
|
||||
page_cur_t cur;
|
||||
ibool ret = TRUE;
|
||||
#ifndef DBUG_OFF
|
||||
ulint nth = 1;
|
||||
#endif /* !DBUG_OFF */
|
||||
|
@ -4576,17 +4648,13 @@ btr_index_page_validate(
|
|||
page_cur_get_page(&cur), 0))
|
||||
== 1););
|
||||
|
||||
page_cur_move_to_next(&cur);
|
||||
|
||||
for (;;) {
|
||||
while (page_cur_move_to_next(&cur)) {
|
||||
if (page_cur_is_after_last(&cur)) {
|
||||
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
|
||||
|
||||
return(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Verify that page_rec_get_nth_const() is correctly
|
||||
|
@ -4598,11 +4666,9 @@ btr_index_page_validate(
|
|||
cur.rec)));
|
||||
ut_a(nth++ == page_rec_get_n_recs_before(
|
||||
cur.rec)););
|
||||
|
||||
page_cur_move_to_next(&cur);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
@ -4720,14 +4786,16 @@ btr_validate_level(
|
|||
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
if (page_is_leaf(page)) {
|
||||
corrupted:
|
||||
err = DB_CORRUPTION;
|
||||
goto invalid_page;
|
||||
}
|
||||
|
||||
page_cur_set_before_first(block, &cursor);
|
||||
page_cur_move_to_next(&cursor);
|
||||
if (!(node_ptr = page_cur_move_to_next(&cursor))) {
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
node_ptr = page_cur_get_rec(&cursor);
|
||||
offsets = rec_get_offsets(node_ptr, index, offsets, 0,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
|
@ -4851,12 +4919,16 @@ func_exit:
|
|||
}
|
||||
|
||||
if (!(rec = page_rec_get_prev(page_get_supremum_rec(page)))) {
|
||||
broken_links:
|
||||
btr_validate_report1(index, level, block);
|
||||
fputs("InnoDB: broken record links\n", stderr);
|
||||
goto invalid_page;
|
||||
}
|
||||
right_rec = page_rec_get_next(page_get_infimum_rec(
|
||||
right_page));
|
||||
if (!(right_rec =
|
||||
page_rec_get_next(page_get_infimum_rec(right_page)))) {
|
||||
goto broken_links;
|
||||
}
|
||||
|
||||
offsets = rec_get_offsets(rec, index, offsets,
|
||||
page_is_leaf(page)
|
||||
? index->n_core_fields : 0,
|
||||
|
@ -4869,7 +4941,7 @@ func_exit:
|
|||
/* For spatial index, we cannot guarantee the key ordering
|
||||
across pages, so skip the record compare verification for
|
||||
now. Will enhanced in special R-Tree index validation scheme */
|
||||
if (!dict_index_is_spatial(index)
|
||||
if (!index->is_spatial()
|
||||
&& cmp_rec_rec(rec, right_rec,
|
||||
offsets, offsets2, index) >= 0) {
|
||||
|
||||
|
@ -4887,19 +4959,26 @@ func_exit:
|
|||
fputs("InnoDB: record ", stderr);
|
||||
rec = page_rec_get_next(
|
||||
page_get_infimum_rec(right_page));
|
||||
rec_print(stderr, rec, index);
|
||||
if (rec) {
|
||||
rec_print(stderr, rec, index);
|
||||
}
|
||||
putc('\n', stderr);
|
||||
err = DB_CORRUPTION;
|
||||
err = DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
if (level > 0 && left_page_no == FIL_NULL
|
||||
&& !(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
|
||||
page_rec_get_next(page_get_infimum_rec(page)),
|
||||
page_is_comp(page)))) {
|
||||
btr_validate_report1(index, level, block);
|
||||
ib::error() << "Missing REC_INFO_MIN_REC_FLAG";
|
||||
if (!level || left_page_no != FIL_NULL) {
|
||||
} else if (const rec_t* first =
|
||||
page_rec_get_next_const(page_get_infimum_rec(page))) {
|
||||
if (!(REC_INFO_MIN_REC_FLAG
|
||||
& rec_get_info_bits(first, page_is_comp(page)))) {
|
||||
btr_validate_report1(index, level, block);
|
||||
ib::error() << "Missing REC_INFO_MIN_REC_FLAG";
|
||||
err = DB_CORRUPTION;
|
||||
}
|
||||
} else {
|
||||
err = DB_CORRUPTION;
|
||||
goto node_ptr_fails;
|
||||
}
|
||||
|
||||
/* Similarly skip the father node check for spatial index for now,
|
||||
|
@ -4908,15 +4987,17 @@ func_exit:
|
|||
in parent level and linked pages in the child level.
|
||||
2) Search parent from root is very costly for R-tree.
|
||||
We will add special validation mechanism for R-tree later (WL #7520) */
|
||||
if (!dict_index_is_spatial(index)
|
||||
&& block->page.id().page_no() != dict_index_get_page(index)) {
|
||||
|
||||
if (!index->is_spatial()
|
||||
&& block->page.id().page_no() != index->page) {
|
||||
/* Check father node pointers */
|
||||
rec_t* node_ptr;
|
||||
rec_t* node_ptr
|
||||
= page_rec_get_next(page_get_infimum_rec(page));
|
||||
if (!node_ptr) {
|
||||
err = DB_CORRUPTION;
|
||||
goto node_ptr_fails;
|
||||
}
|
||||
|
||||
btr_cur_position(
|
||||
index, page_rec_get_next(page_get_infimum_rec(page)),
|
||||
block, &node_cur);
|
||||
btr_cur_position(index, node_ptr, block, &node_cur);
|
||||
offsets = btr_page_get_father_node_ptr_for_validate(
|
||||
offsets, heap, &node_cur, &mtr);
|
||||
|
||||
|
@ -4965,17 +5046,15 @@ func_exit:
|
|||
goto node_ptr_fails;
|
||||
}
|
||||
|
||||
if (!page_is_leaf(page)) {
|
||||
if (page_is_leaf(page)) {
|
||||
} else if (const rec_t* first_rec =
|
||||
page_rec_get_next(page_get_infimum_rec(page))) {
|
||||
node_ptr_tuple = dict_index_build_node_ptr(
|
||||
index,
|
||||
page_rec_get_next(page_get_infimum_rec(page)),
|
||||
index, first_rec,
|
||||
0, heap, btr_page_get_level(page));
|
||||
|
||||
if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
|
||||
offsets)) {
|
||||
const rec_t* first_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(page));
|
||||
|
||||
btr_validate_report1(index, level, block);
|
||||
|
||||
ib::error() << "Node ptrs differ on levels > 0";
|
||||
|
@ -4985,14 +5064,17 @@ func_exit:
|
|||
fputs("InnoDB: first rec ", stderr);
|
||||
rec_print(stderr, first_rec, index);
|
||||
putc('\n', stderr);
|
||||
err = DB_CORRUPTION;
|
||||
err = DB_CORRUPTION;
|
||||
goto node_ptr_fails;
|
||||
}
|
||||
} else {
|
||||
err = DB_CORRUPTION;
|
||||
goto node_ptr_fails;
|
||||
}
|
||||
|
||||
if (left_page_no == FIL_NULL) {
|
||||
if (page_has_prev(father_page)
|
||||
|| node_ptr != page_rec_get_next(
|
||||
|| node_ptr != page_rec_get_next(
|
||||
page_get_infimum_rec(father_page))) {
|
||||
err = DB_CORRUPTION;
|
||||
goto node_ptr_fails;
|
||||
|
@ -5006,11 +5088,8 @@ func_exit:
|
|||
err = DB_CORRUPTION;
|
||||
goto node_ptr_fails;
|
||||
}
|
||||
} else {
|
||||
const rec_t* right_node_ptr;
|
||||
|
||||
right_node_ptr = page_rec_get_next(node_ptr);
|
||||
|
||||
} else if (const rec_t* right_node_ptr
|
||||
= page_rec_get_next(node_ptr)) {
|
||||
if (!lockout && rightmost_child) {
|
||||
|
||||
/* To obey latch order of tree blocks,
|
||||
|
@ -5041,11 +5120,12 @@ func_exit:
|
|||
}
|
||||
|
||||
btr_cur_position(
|
||||
index, page_rec_get_next(
|
||||
page_get_infimum_rec(
|
||||
buf_block_get_frame(
|
||||
right_block))),
|
||||
index,
|
||||
page_get_infimum_rec(right_block->page.frame),
|
||||
right_block, &right_node_cur);
|
||||
if (!page_cur_move_to_next(&right_node_cur.page_cur)) {
|
||||
goto node_pointer_corrupted;
|
||||
}
|
||||
|
||||
offsets = btr_page_get_father_node_ptr_for_validate(
|
||||
offsets, heap, &right_node_cur, &mtr);
|
||||
|
@ -5055,6 +5135,7 @@ func_exit:
|
|||
|
||||
if (btr_cur_get_rec(&right_node_cur)
|
||||
!= right_node_ptr) {
|
||||
node_pointer_corrupted:
|
||||
err = DB_CORRUPTION;
|
||||
fputs("InnoDB: node pointer to"
|
||||
" the right page is wrong\n",
|
||||
|
@ -5092,6 +5173,8 @@ func_exit:
|
|||
block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1199,6 +1199,9 @@ err_exit:
|
|||
|
||||
first_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(last_block->page.frame));
|
||||
/* 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. */
|
||||
|
|
|
@ -403,15 +403,13 @@ unreadable:
|
|||
ut_ad(page_cur_is_before_first(&cur.page_cur));
|
||||
ut_ad(page_is_leaf(cur.page_cur.block->page.frame));
|
||||
|
||||
page_cur_move_to_next(&cur.page_cur);
|
||||
|
||||
const rec_t* rec = 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_get_info_bits(rec, comp);
|
||||
const ulint info_bits = rec ? rec_get_info_bits(rec, comp) : 0;
|
||||
|
||||
if (page_rec_is_supremum(rec)
|
||||
|| !(info_bits & REC_INFO_MIN_REC_FLAG)) {
|
||||
if (!index->is_instant()) {
|
||||
if (rec && !index->is_instant()) {
|
||||
/* The FIL_PAGE_TYPE_INSTANT and PAGE_INSTANT may be
|
||||
assigned even if instant ADD COLUMN was not
|
||||
committed. Changes to these page header fields are not
|
||||
|
@ -884,6 +882,21 @@ btr_cur_latch_for_root_leaf(
|
|||
return(RW_NO_LATCH); /* avoid compiler warnings */
|
||||
}
|
||||
|
||||
/** @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)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (left == right)
|
||||
return true;
|
||||
left= page_rec_get_next_const(left);
|
||||
}
|
||||
while (left && val--);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Detects whether the modifying record might need a modifying tree structure.
|
||||
@param[in] index index
|
||||
@param[in] page page
|
||||
|
@ -1914,22 +1927,28 @@ retry_page_get:
|
|||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
} else if (height == 0 && btr_search_enabled
|
||||
&& !(tuple->info_bits & REC_INFO_MIN_REC_FLAG)
|
||||
&& !dict_index_is_spatial(index)) {
|
||||
&& index->is_btree()) {
|
||||
/* The adaptive hash index is only used when searching
|
||||
for leaf pages (height==0), but not in r-trees.
|
||||
We only need the byte prefix comparison for the purpose
|
||||
of updating the adaptive hash index. */
|
||||
page_cur_search_with_match_bytes(
|
||||
if (page_cur_search_with_match_bytes(
|
||||
block, index, tuple, page_mode, &up_match, &up_bytes,
|
||||
&low_match, &low_bytes, page_cursor);
|
||||
&low_match, &low_bytes, page_cursor)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
#endif /* BTR_CUR_HASH_ADAPT */
|
||||
} else {
|
||||
/* Search for complete index fields. */
|
||||
up_bytes = low_bytes = 0;
|
||||
page_cur_search_with_match(
|
||||
if (page_cur_search_with_match(
|
||||
block, index, tuple, page_mode, &up_match,
|
||||
&low_match, page_cursor,
|
||||
need_path ? cursor->rtr_info : NULL);
|
||||
need_path ? cursor->rtr_info : nullptr)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is the desired level, leave the loop */
|
||||
|
@ -2097,6 +2116,11 @@ need_opposite_intention:
|
|||
|
||||
ut_ad(upper_rw_latch == RW_X_LATCH);
|
||||
|
||||
if (UNIV_UNLIKELY(!first_rec)) {
|
||||
corrupted:
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
if (node_ptr == first_rec
|
||||
|| page_rec_is_last(node_ptr, page)) {
|
||||
detected_same_key_root = true;
|
||||
|
@ -2131,8 +2155,7 @@ need_opposite_intention:
|
|||
detected_same_key_root = true;
|
||||
}
|
||||
} else {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2241,11 +2264,14 @@ need_opposite_intention:
|
|||
? cursor->rtr_info : NULL;
|
||||
|
||||
for (ulint i = 0; i < n_blocks; i++) {
|
||||
page_cur_search_with_match(
|
||||
if (page_cur_search_with_match(
|
||||
tree_blocks[i], index, tuple,
|
||||
page_mode, &up_match,
|
||||
&low_match, page_cursor,
|
||||
rtr_info);
|
||||
rtr_info)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
goto search_loop;
|
||||
|
@ -2678,13 +2704,11 @@ btr_cur_open_at_index_side(
|
|||
|
||||
ut_ad(height > 0);
|
||||
|
||||
if (from_left) {
|
||||
page_cur_move_to_next(page_cursor);
|
||||
} else {
|
||||
if (!page_cur_move_to_prev(page_cursor)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto exit_loop;
|
||||
}
|
||||
if (from_left
|
||||
? !page_cur_move_to_next(page_cursor)
|
||||
: !page_cur_move_to_prev(page_cursor)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto exit_loop;
|
||||
}
|
||||
|
||||
height--;
|
||||
|
@ -3117,7 +3141,7 @@ btr_cur_insert_if_possible(
|
|||
|
||||
/*************************************************************//**
|
||||
For an insert, checks the locks and does the undo logging if desired.
|
||||
@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
|
||||
@return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL, or error number */
|
||||
UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,5,6)))
|
||||
dberr_t
|
||||
btr_cur_ins_lock_and_undo(
|
||||
|
@ -3268,7 +3292,7 @@ It is assumed that mtr holds an x-latch on the page. The operation does
|
|||
not succeed if there is too little space on the page. If there is just
|
||||
one record on the page, the insert will always succeed; this is to
|
||||
prevent trying to split a page with just one record.
|
||||
@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
|
||||
@return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL, or error number */
|
||||
dberr_t
|
||||
btr_cur_optimistic_insert(
|
||||
/*======================*/
|
||||
|
@ -3736,7 +3760,7 @@ func_exit:
|
|||
|
||||
/*************************************************************//**
|
||||
For an update, checks the locks and does the undo logging.
|
||||
@return DB_SUCCESS, DB_WAIT_LOCK, or error number */
|
||||
@return DB_SUCCESS, DB_LOCK_WAIT, or error number */
|
||||
UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
|
||||
dberr_t
|
||||
btr_cur_upd_lock_and_undo(
|
||||
|
@ -4682,8 +4706,7 @@ any_extern:
|
|||
rec = btr_cur_insert_if_possible(cursor, new_entry, offsets, heap,
|
||||
0/*n_ext*/, mtr);
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(update->is_metadata())) {
|
||||
|
@ -4701,8 +4724,11 @@ any_extern:
|
|||
block->page.id());
|
||||
}
|
||||
|
||||
page_cur_move_to_next(page_cursor);
|
||||
ut_ad(err == DB_SUCCESS);
|
||||
if (!page_cur_move_to_next(page_cursor)) {
|
||||
corrupted:
|
||||
err = DB_CORRUPTION;
|
||||
}
|
||||
|
||||
func_exit:
|
||||
if (!(flags & BTR_KEEP_IBUF_BITMAP)
|
||||
|
@ -5454,6 +5480,10 @@ btr_cur_optimistic_delete(
|
|||
dict_index_t* index = cursor->index;
|
||||
const rec_t* first_rec = page_rec_get_next_const(
|
||||
page_get_infimum_rec(block->page.frame));
|
||||
if (UNIV_UNLIKELY(!first_rec)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
ut_ad(!index->is_instant()
|
||||
|| rec_is_metadata(first_rec, *index));
|
||||
const bool is_metadata = rec_is_metadata(rec, *index);
|
||||
|
@ -5683,6 +5713,10 @@ btr_cur_pessimistic_delete(
|
|||
|
||||
const rec_t* first_rec = page_rec_get_next_const(
|
||||
page_get_infimum_rec(page));
|
||||
if (UNIV_UNLIKELY(!first_rec)) {
|
||||
*err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
ut_ad(!index->is_instant()
|
||||
|| rec_is_metadata(first_rec, *index));
|
||||
if (is_metadata || !index->is_instant()
|
||||
|
@ -5729,7 +5763,11 @@ discard_page:
|
|||
goto return_after_reservations;
|
||||
}
|
||||
|
||||
next_rec = page_rec_get_next(rec);
|
||||
if (UNIV_UNLIKELY(!(next_rec = page_rec_get_next(rec)))) {
|
||||
ut_ad(!ret);
|
||||
*err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (!page_has_prev(page)) {
|
||||
/* If we delete the leftmost node pointer on a
|
||||
|
@ -5996,9 +6034,10 @@ public:
|
|||
if (dtuple_get_n_fields(&m_tuple) > 0)
|
||||
{
|
||||
m_up_bytes= m_low_bytes= 0;
|
||||
page_cur_search_with_match(m_block, index(), &m_tuple, m_page_mode,
|
||||
&m_up_match, &m_low_match, &m_page_cur,
|
||||
nullptr);
|
||||
if (page_cur_search_with_match(m_block, index(), &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));
|
||||
}
|
||||
else if (left)
|
||||
|
@ -6006,7 +6045,8 @@ public:
|
|||
page_cur_set_before_first(m_block, &m_page_cur);
|
||||
if (level)
|
||||
{
|
||||
page_cur_move_to_next(&m_page_cur);
|
||||
if (!page_cur_move_to_next(&m_page_cur))
|
||||
return false;
|
||||
m_nth_rec= 1;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -259,9 +259,10 @@ 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);
|
||||
page_cur_move_to_next(&cur);
|
||||
while (page_cur_get_rec(&cur) != page_get_supremum_rec(page)) {
|
||||
rec_t* cur_rec = page_cur_get_rec(&cur);
|
||||
while (rec_t* cur_rec = page_cur_move_to_next(&cur)) {
|
||||
if (page_rec_is_supremum(cur_rec)) {
|
||||
break;
|
||||
}
|
||||
offsets = rec_get_offsets(cur_rec, index, offsets, n_core,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
ulint rec_size = rec_offs_size(offsets);
|
||||
|
@ -271,7 +272,6 @@ btr_defragment_calc_n_recs_for_size(
|
|||
break;
|
||||
}
|
||||
n_recs ++;
|
||||
page_cur_move_to_next(&cur);
|
||||
}
|
||||
*n_recs_size = size;
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
|
@ -356,8 +356,9 @@ btr_defragment_merge_pages(
|
|||
target_n_recs = n_recs_to_move;
|
||||
dberr_t err;
|
||||
while (n_recs_to_move > 0) {
|
||||
rec = page_rec_get_nth(from_page,
|
||||
n_recs_to_move + 1);
|
||||
if (!(rec = page_rec_get_nth(from_page, n_recs_to_move + 1))) {
|
||||
return nullptr;
|
||||
}
|
||||
orig_pred = page_copy_rec_list_start(
|
||||
to_block, from_block, rec, index, mtr, &err);
|
||||
if (orig_pred)
|
||||
|
@ -439,14 +440,17 @@ btr_defragment_merge_pages(
|
|||
}
|
||||
rec = page_rec_get_next(
|
||||
page_get_infimum_rec(from_page));
|
||||
if (!rec) {
|
||||
return nullptr;
|
||||
}
|
||||
node_ptr = dict_index_build_node_ptr(
|
||||
index, rec, page_get_page_no(from_page),
|
||||
heap, level);
|
||||
if (btr_insert_on_non_leaf_level(0, index, level+1,
|
||||
node_ptr, mtr)
|
||||
!= DB_SUCCESS) {
|
||||
node_ptr, mtr)
|
||||
!= DB_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
to_block = from_block;
|
||||
}
|
||||
|
|
|
@ -176,10 +176,16 @@ before_first:
|
|||
} else if (page_rec_is_infimum_low(offs)) {
|
||||
rec = page_rec_get_next(rec);
|
||||
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
ut_ad("corrupted page" == 0);
|
||||
goto before_first;
|
||||
}
|
||||
|
||||
if (rec_is_metadata(rec, *index)) {
|
||||
ut_ad(!page_has_prev(block->page.frame));
|
||||
rec = page_rec_get_next(rec);
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
ut_ad(rec);
|
||||
if (!rec || page_rec_is_supremum(rec)) {
|
||||
goto before_first;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -788,8 +788,20 @@ btr_search_check_guess(
|
|||
|
||||
rec = btr_cur_get_rec(cursor);
|
||||
|
||||
ut_ad(page_rec_is_user_rec(rec));
|
||||
ut_ad(page_rec_is_leaf(rec));
|
||||
if (UNIV_UNLIKELY(!page_rec_is_user_rec(rec)
|
||||
|| !page_rec_is_leaf(rec))) {
|
||||
ut_ad("corrupted index" == 0);
|
||||
return false;
|
||||
} else if (cursor->index->table->not_redundant()) {
|
||||
switch (rec_get_status(rec)) {
|
||||
case REC_STATUS_INSTANT:
|
||||
case REC_STATUS_ORDINARY:
|
||||
break;
|
||||
default:
|
||||
ut_ad("corrupted index" == 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
match = 0;
|
||||
|
||||
|
@ -847,6 +859,17 @@ btr_search_check_guess(
|
|||
goto exit_func;
|
||||
}
|
||||
|
||||
if (cursor->index->table->not_redundant()) {
|
||||
switch (rec_get_status(prev_rec)) {
|
||||
case REC_STATUS_INSTANT:
|
||||
case REC_STATUS_ORDINARY:
|
||||
break;
|
||||
default:
|
||||
ut_ad("corrupted index" == 0);
|
||||
goto exit_func;
|
||||
}
|
||||
}
|
||||
|
||||
offsets = rec_get_offsets(prev_rec, cursor->index, offsets,
|
||||
cursor->index->n_core_fields,
|
||||
n_unique, &heap);
|
||||
|
@ -862,15 +885,31 @@ btr_search_check_guess(
|
|||
|
||||
const rec_t* next_rec = page_rec_get_next(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))) {
|
||||
cursor->up_match = 0;
|
||||
success = TRUE;
|
||||
success = true;
|
||||
}
|
||||
|
||||
goto exit_func;
|
||||
}
|
||||
|
||||
if (cursor->index->table->not_redundant()) {
|
||||
switch (rec_get_status(next_rec)) {
|
||||
case REC_STATUS_INSTANT:
|
||||
case REC_STATUS_ORDINARY:
|
||||
break;
|
||||
default:
|
||||
ut_ad("corrupted index" == 0);
|
||||
goto exit_func;
|
||||
}
|
||||
}
|
||||
|
||||
offsets = rec_get_offsets(next_rec, cursor->index, offsets,
|
||||
cursor->index->n_core_fields,
|
||||
n_unique, &heap);
|
||||
|
@ -1245,14 +1284,7 @@ void btr_search_drop_page_hash_index(buf_block_t* block)
|
|||
{
|
||||
ulint n_fields;
|
||||
ulint n_bytes;
|
||||
const page_t* page;
|
||||
const rec_t* rec;
|
||||
ulint fold;
|
||||
ulint prev_fold;
|
||||
ulint n_cached;
|
||||
ulint n_recs;
|
||||
ulint* folds;
|
||||
ulint i;
|
||||
mem_heap_t* heap;
|
||||
rec_offs* offsets;
|
||||
|
||||
|
@ -1323,33 +1355,50 @@ retry:
|
|||
|
||||
ut_a(n_fields > 0 || n_bytes > 0);
|
||||
|
||||
page = block->page.frame;
|
||||
n_recs = page_get_n_recs(page);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate and cache fold values into an array for fast deletion
|
||||
from the hash index */
|
||||
|
||||
folds = (ulint*) ut_malloc_nokey(n_recs * sizeof(ulint));
|
||||
|
||||
n_cached = 0;
|
||||
|
||||
rec = page_get_infimum_rec(page);
|
||||
rec = page_rec_get_next_low(rec, page_is_comp(page));
|
||||
if (rec_is_metadata(rec, *index)) {
|
||||
|
||||
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));
|
||||
if (!--n_recs) {
|
||||
/* The page only contains the hidden metadata record
|
||||
for instant ALTER TABLE that the adaptive hash index
|
||||
never points to. */
|
||||
folds = nullptr;
|
||||
goto all_deleted;
|
||||
}
|
||||
}
|
||||
|
||||
prev_fold = 0;
|
||||
folds = (ulint*) ut_malloc_nokey(n_recs * sizeof(ulint));
|
||||
heap = nullptr;
|
||||
offsets = nullptr;
|
||||
|
||||
heap = NULL;
|
||||
offsets = NULL;
|
||||
|
||||
while (!page_rec_is_supremum(rec)) {
|
||||
while (rec) {
|
||||
if (n_cached >= n_recs) {
|
||||
ut_ad(page_rec_is_supremum(rec));
|
||||
break;
|
||||
}
|
||||
ut_ad(page_rec_is_user_rec(rec));
|
||||
offsets = rec_get_offsets(
|
||||
rec, index, offsets, index->n_core_fields,
|
||||
btr_search_get_n_fields(n_fields, n_bytes),
|
||||
&heap);
|
||||
fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id);
|
||||
const ulint fold = rec_fold(rec, offsets, n_fields, n_bytes,
|
||||
index_id);
|
||||
|
||||
if (fold == prev_fold && prev_fold != 0) {
|
||||
|
||||
|
@ -1358,11 +1407,13 @@ retry:
|
|||
|
||||
/* Remove all hash nodes pointing to this page from the
|
||||
hash chain */
|
||||
folds[n_cached++] = fold;
|
||||
|
||||
folds[n_cached] = fold;
|
||||
n_cached++;
|
||||
next_rec:
|
||||
rec = page_rec_get_next_low(rec, page_rec_is_comp(rec));
|
||||
if (!rec || page_rec_is_supremum(rec)) {
|
||||
break;
|
||||
}
|
||||
prev_fold = fold;
|
||||
}
|
||||
|
||||
|
@ -1370,6 +1421,7 @@ next_rec:
|
|||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
all_deleted:
|
||||
if (!is_freed) {
|
||||
part->latch.wr_lock(SRW_LOCK_CALL);
|
||||
|
||||
|
@ -1394,7 +1446,7 @@ next_rec:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_cached; i++) {
|
||||
for (ulint i = 0; i < n_cached; i++) {
|
||||
ha_remove_all_nodes_to_page(&part->table, part->heap,
|
||||
folds[i], page);
|
||||
}
|
||||
|
@ -1408,7 +1460,7 @@ next_rec:
|
|||
}
|
||||
}
|
||||
|
||||
block->index = NULL;
|
||||
block->index = nullptr;
|
||||
|
||||
MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_REMOVED);
|
||||
MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_REMOVED, n_cached);
|
||||
|
@ -1472,7 +1524,6 @@ btr_search_build_page_hash_index(
|
|||
bool left_side)
|
||||
{
|
||||
const rec_t* rec;
|
||||
const rec_t* next_rec;
|
||||
ulint fold;
|
||||
ulint next_fold;
|
||||
ulint n_cached;
|
||||
|
@ -1538,10 +1589,11 @@ btr_search_build_page_hash_index(
|
|||
}
|
||||
|
||||
rec = page_rec_get_next_const(page_get_infimum_rec(page));
|
||||
if (!rec) return;
|
||||
|
||||
if (rec_is_metadata(rec, *index)) {
|
||||
rec = page_rec_get_next_const(rec);
|
||||
if (!--n_recs) return;
|
||||
if (!rec || !--n_recs) return;
|
||||
}
|
||||
|
||||
/* Calculate and cache fold values and corresponding records into
|
||||
|
@ -1571,9 +1623,7 @@ btr_search_build_page_hash_index(
|
|||
n_cached++;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
next_rec = page_rec_get_next_const(rec);
|
||||
|
||||
while (const rec_t* next_rec = page_rec_get_next_const(rec)) {
|
||||
if (page_rec_is_supremum(next_rec)) {
|
||||
|
||||
if (!left_side) {
|
||||
|
@ -1906,12 +1956,15 @@ 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 (ha_search_and_update_if_found(
|
||||
&btr_search_sys.get_part(*cursor->index)->table,
|
||||
cursor->fold, rec, block,
|
||||
page_rec_get_next(rec))) {
|
||||
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_UPDATED);
|
||||
if (const rec_t *new_rec = page_rec_get_next_const(rec)) {
|
||||
if (ha_search_and_update_if_found(
|
||||
&btr_search_sys.get_part(*cursor->index)
|
||||
->table,
|
||||
cursor->fold, rec, block, new_rec)) {
|
||||
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_UPDATED);
|
||||
}
|
||||
} else {
|
||||
ut_ad("corrupted page" == 0);
|
||||
}
|
||||
|
||||
func_exit:
|
||||
|
@ -1976,6 +2029,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor,
|
|||
|
||||
if (index != cursor->index) {
|
||||
ut_ad(index->id == cursor->index->id);
|
||||
drop:
|
||||
btr_search_drop_page_hash_index(block);
|
||||
return;
|
||||
}
|
||||
|
@ -1988,7 +2042,9 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor,
|
|||
const bool left_side = block->curr_left_side;
|
||||
|
||||
ins_rec = page_rec_get_next_const(rec);
|
||||
if (UNIV_UNLIKELY(!ins_rec)) goto drop;
|
||||
next_rec = page_rec_get_next_const(ins_rec);
|
||||
if (UNIV_UNLIKELY(!next_rec)) goto drop;
|
||||
|
||||
offsets = rec_get_offsets(ins_rec, index, offsets,
|
||||
index->n_core_fields,
|
||||
|
|
|
@ -1239,7 +1239,7 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
|
|||
const ulint n_core = page_is_leaf(page)
|
||||
? index->n_core_fields : 0;
|
||||
|
||||
if (!page_rec_is_supremum(rec)) {
|
||||
if (rec && !page_rec_is_supremum(rec)) {
|
||||
not_empty_flag = 1;
|
||||
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
|
||||
n_core,
|
||||
|
@ -1254,7 +1254,7 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
|
|||
while (!page_rec_is_supremum(rec)) {
|
||||
ulint matched_fields;
|
||||
rec_t* next_rec = page_rec_get_next(rec);
|
||||
if (page_rec_is_supremum(next_rec)) {
|
||||
if (!next_rec || page_rec_is_supremum(next_rec)) {
|
||||
total_external_size +=
|
||||
btr_rec_get_externally_stored_len(
|
||||
rec, offsets_rec);
|
||||
|
@ -1630,12 +1630,11 @@ dict_stats_analyze_index_level(
|
|||
|
||||
if (btr_pcur_open_at_index_side(
|
||||
true, index, BTR_SEARCH_TREE_ALREADY_S_LATCHED,
|
||||
&pcur, true, level, mtr) != DB_SUCCESS) {
|
||||
&pcur, true, level, mtr) != DB_SUCCESS
|
||||
|| !btr_pcur_move_to_next_on_page(&pcur)) {
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
btr_pcur_move_to_next_on_page(&pcur);
|
||||
|
||||
page = btr_pcur_get_page(&pcur);
|
||||
|
||||
/* The page must not be empty, except when
|
||||
|
@ -1877,6 +1876,36 @@ func_exit:
|
|||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************//**
|
||||
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 */
|
||||
{
|
||||
const page_t *const page= page_align(rec);
|
||||
|
||||
if (page_is_comp(page))
|
||||
{
|
||||
for (rec= page_rec_get_next_low(rec, TRUE);
|
||||
rec && rec_get_deleted_flag(rec, TRUE);
|
||||
rec= page_rec_get_next_low(rec, TRUE));
|
||||
return rec ? rec : page + PAGE_NEW_SUPREMUM;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (rec= page_rec_get_next_low(rec, FALSE);
|
||||
rec && rec_get_deleted_flag(rec, FALSE);
|
||||
rec= page_rec_get_next_low(rec, FALSE));
|
||||
return rec ? rec : page + PAGE_OLD_SUPREMUM;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
|
@ -1934,7 +1963,7 @@ dict_stats_scan_page(
|
|||
|
||||
rec = get_next(page_get_infimum_rec(page));
|
||||
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
if (!rec || page_rec_is_supremum(rec)) {
|
||||
/* the page is empty or contains only delete-marked records */
|
||||
*n_diff = 0;
|
||||
*out_rec = NULL;
|
||||
|
@ -1953,7 +1982,7 @@ dict_stats_scan_page(
|
|||
|
||||
*n_diff = 1;
|
||||
|
||||
while (!page_rec_is_supremum(next_rec)) {
|
||||
while (next_rec && !page_rec_is_supremum(next_rec)) {
|
||||
|
||||
ulint matched_fields;
|
||||
|
||||
|
@ -2242,12 +2271,11 @@ dict_stats_analyze_index_for_n_prefix(
|
|||
if (btr_pcur_open_at_index_side(true, index,
|
||||
BTR_SEARCH_TREE_ALREADY_S_LATCHED,
|
||||
&pcur, true, n_diff_data->level, mtr)
|
||||
!= DB_SUCCESS) {
|
||||
!= DB_SUCCESS
|
||||
|| !btr_pcur_move_to_next_on_page(&pcur)) {
|
||||
return;
|
||||
}
|
||||
|
||||
btr_pcur_move_to_next_on_page(&pcur);
|
||||
|
||||
page = btr_pcur_get_page(&pcur);
|
||||
|
||||
const rec_t* first_rec = btr_pcur_get_rec(&pcur);
|
||||
|
|
|
@ -405,21 +405,24 @@ update_mbr:
|
|||
}
|
||||
|
||||
/* Insert the new rec. */
|
||||
page_cur_search_with_match(block, index, node_ptr,
|
||||
PAGE_CUR_LE , &up_match, &low_match,
|
||||
btr_cur_get_page_cur(cursor), NULL);
|
||||
if (page_cur_search_with_match(block, index, node_ptr,
|
||||
PAGE_CUR_LE,
|
||||
&up_match, &low_match,
|
||||
btr_cur_get_page_cur(cursor),
|
||||
NULL)) {
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
err = btr_cur_optimistic_insert(flags, cursor, &insert_offsets,
|
||||
&heap, node_ptr, &insert_rec,
|
||||
&dummy_big_rec, 0, NULL, mtr);
|
||||
|
||||
if (!ins_suc && err == DB_SUCCESS) {
|
||||
ins_suc = true;
|
||||
}
|
||||
|
||||
/* If optimistic insert fail, try reorganize the page
|
||||
and insert again. */
|
||||
if (err != DB_SUCCESS && ins_suc) {
|
||||
if (err == DB_SUCCESS) {
|
||||
ins_suc = true;
|
||||
} else if (ins_suc) {
|
||||
ut_ad(err == DB_FAIL);
|
||||
err = btr_page_reorganize(btr_cur_get_page_cur(cursor),
|
||||
index, mtr);
|
||||
if (err == DB_SUCCESS) {
|
||||
|
@ -431,6 +434,7 @@ update_mbr:
|
|||
|
||||
/* Will do pessimistic insert */
|
||||
if (err != DB_SUCCESS) {
|
||||
ut_ad(err == DB_FAIL);
|
||||
ins_suc = false;
|
||||
}
|
||||
}
|
||||
|
@ -462,10 +466,14 @@ update_mbr:
|
|||
cur2_pno = btr_node_ptr_get_child_page_no(cur2_rec, offsets2);
|
||||
if ((del_page_no != cur2_pno)
|
||||
|| (cur2_rec == insert_rec)) {
|
||||
cur2_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(page));
|
||||
cur2_rec = page_get_infimum_rec(page);
|
||||
|
||||
while ((cur2_rec
|
||||
= page_rec_get_next(cur2_rec))) {
|
||||
if (page_rec_is_supremum(cur2_rec)) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (!page_rec_is_supremum(cur2_rec)) {
|
||||
offsets2 = rec_get_offsets(cur2_rec, index,
|
||||
NULL,
|
||||
n_core,
|
||||
|
@ -480,10 +488,7 @@ update_mbr:
|
|||
break;
|
||||
}
|
||||
}
|
||||
cur2_rec = page_rec_get_next(cur2_rec);
|
||||
}
|
||||
|
||||
ut_ad(!page_rec_is_supremum(cur2_rec));
|
||||
}
|
||||
|
||||
rec_info = rec_get_info_bits(cur2_rec,
|
||||
|
@ -529,7 +534,7 @@ update_mbr:
|
|||
|| (REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
|
||||
page_rec_get_next(page_get_infimum_rec(page)),
|
||||
page_is_comp(page))));
|
||||
|
||||
err_exit:
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
|
@ -556,11 +561,10 @@ rtr_adjust_upper_level(
|
|||
rec_offs* offsets;
|
||||
mem_heap_t* heap;
|
||||
ulint level;
|
||||
dtuple_t* node_ptr_upper;
|
||||
dtuple_t* node_ptr_upper = nullptr;
|
||||
page_cur_t* page_cursor;
|
||||
lock_prdt_t prdt;
|
||||
lock_prdt_t new_prdt;
|
||||
dberr_t err;
|
||||
big_rec_t* dummy_big_rec;
|
||||
rec_t* rec;
|
||||
|
||||
|
@ -597,29 +601,32 @@ rtr_adjust_upper_level(
|
|||
}
|
||||
}
|
||||
|
||||
/* Insert the node for the new page. */
|
||||
node_ptr_upper = rtr_index_build_node_ptr(
|
||||
index, new_mbr,
|
||||
page_rec_get_next(page_get_infimum_rec(new_block->page.frame)),
|
||||
new_page_no, heap);
|
||||
dberr_t err;
|
||||
|
||||
ulint up_match = 0;
|
||||
ulint low_match = 0;
|
||||
|
||||
buf_block_t* father_block = btr_cur_get_block(&cursor);
|
||||
|
||||
page_cur_search_with_match(
|
||||
father_block, index, node_ptr_upper,
|
||||
PAGE_CUR_LE , &up_match, &low_match,
|
||||
btr_cur_get_page_cur(&cursor), NULL);
|
||||
|
||||
err = btr_cur_optimistic_insert(
|
||||
flags
|
||||
| BTR_NO_LOCKING_FLAG
|
||||
| BTR_KEEP_SYS_FLAG
|
||||
| BTR_NO_UNDO_LOG_FLAG,
|
||||
&cursor, &offsets, &heap,
|
||||
node_ptr_upper, &rec, &dummy_big_rec, 0, NULL, mtr);
|
||||
if (const rec_t* first = page_rec_get_next_const(
|
||||
page_get_infimum_rec(new_block->page.frame))) {
|
||||
/* Insert the node for the new page. */
|
||||
node_ptr_upper = rtr_index_build_node_ptr(
|
||||
index, new_mbr, first, new_page_no, heap);
|
||||
ulint up_match = 0, low_match = 0;
|
||||
err = page_cur_search_with_match(btr_cur_get_block(&cursor),
|
||||
index, node_ptr_upper,
|
||||
PAGE_CUR_LE,
|
||||
&up_match, &low_match,
|
||||
btr_cur_get_page_cur(&cursor),
|
||||
NULL)
|
||||
? DB_CORRUPTION
|
||||
: btr_cur_optimistic_insert(flags
|
||||
| BTR_NO_LOCKING_FLAG
|
||||
| BTR_KEEP_SYS_FLAG
|
||||
| BTR_NO_UNDO_LOG_FLAG,
|
||||
&cursor, &offsets, &heap,
|
||||
node_ptr_upper, &rec,
|
||||
&dummy_big_rec, 0, NULL,
|
||||
mtr);
|
||||
} else {
|
||||
err = DB_CORRUPTION;
|
||||
}
|
||||
|
||||
if (err == DB_FAIL) {
|
||||
cursor.rtr_info = sea_cur->rtr_info;
|
||||
|
@ -638,23 +645,27 @@ rtr_adjust_upper_level(
|
|||
node_ptr_upper, &rec,
|
||||
&dummy_big_rec, 0, NULL, mtr);
|
||||
cursor.rtr_info = NULL;
|
||||
ut_a(err == DB_SUCCESS);
|
||||
|
||||
mem_heap_free(new_heap);
|
||||
}
|
||||
|
||||
prdt.data = static_cast<void*>(mbr);
|
||||
prdt.op = 0;
|
||||
new_prdt.data = static_cast<void*>(new_mbr);
|
||||
new_prdt.op = 0;
|
||||
if (err == DB_SUCCESS) {
|
||||
prdt.data = static_cast<void*>(mbr);
|
||||
prdt.op = 0;
|
||||
new_prdt.data = static_cast<void*>(new_mbr);
|
||||
new_prdt.op = 0;
|
||||
|
||||
lock_prdt_update_parent(block, new_block, &prdt, &new_prdt,
|
||||
page_cursor->block->page.id());
|
||||
lock_prdt_update_parent(block, new_block, &prdt, &new_prdt,
|
||||
page_cursor->block->page.id());
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
ut_ad(block->zip_size() == index->table->space->zip_size());
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const uint32_t next_page_no = btr_page_get_next(block->page.frame);
|
||||
|
||||
if (next_page_no == FIL_NULL) {
|
||||
|
@ -765,13 +776,15 @@ rtr_split_page_move_rec_list(
|
|||
&new_page_cursor,
|
||||
index, cur_split_node->key, offsets, mtr);
|
||||
|
||||
ut_a(rec);
|
||||
if (UNIV_UNLIKELY
|
||||
(!rec
|
||||
|| !page_cur_move_to_next(&new_page_cursor))) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
lock_rec_restore_from_page_infimum(
|
||||
*new_block, rec, block->page.id());
|
||||
|
||||
page_cur_move_to_next(&new_page_cursor);
|
||||
|
||||
rec_move[moved].new_rec = rec;
|
||||
rec_move[moved].old_rec = cur_split_node->key;
|
||||
rec_move[moved].moved = false;
|
||||
|
@ -913,6 +926,11 @@ func_start:
|
|||
if (!page_has_prev(page) && !page_is_leaf(page)) {
|
||||
first_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(buf_block_get_frame(block)));
|
||||
if (UNIV_UNLIKELY(!first_rec)) {
|
||||
corrupted:
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initial split nodes array. */
|
||||
|
@ -1098,9 +1116,13 @@ func_start:
|
|||
|
||||
/* Reposition the cursor for insert and try insertion */
|
||||
page_cursor = btr_cur_get_page_cur(cursor);
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
page_cur_search(insert_block, cursor->index, tuple,
|
||||
PAGE_CUR_LE, page_cursor);
|
||||
if (page_cur_search_with_match(insert_block, cursor->index, tuple,
|
||||
PAGE_CUR_LE, &up_match, &low_match,
|
||||
page_cursor, nullptr)) {
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* It's possible that the new record is too big to be inserted into
|
||||
the page, and it'll need the second round split in this case.
|
||||
|
@ -1154,7 +1176,7 @@ after_insert:
|
|||
the first ssn value from it after restart server. */
|
||||
|
||||
root_block = btr_root_block_get(cursor->index, RW_SX_LATCH, mtr, err);
|
||||
if (UNIV_UNLIKELY(!root_block)) {
|
||||
if (UNIV_UNLIKELY(!root_block)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1180,6 +1202,9 @@ after_insert:
|
|||
|
||||
rec_t* i_rec = page_rec_get_next(page_get_infimum_rec(
|
||||
buf_block_get_frame(block)));
|
||||
if (UNIV_UNLIKELY(!i_rec)) {
|
||||
goto corrupted;
|
||||
}
|
||||
btr_cur_position(cursor->index, i_rec, block, cursor);
|
||||
|
||||
goto func_start;
|
||||
|
@ -1299,8 +1324,8 @@ rtr_page_copy_rec_list_end_no_locks(
|
|||
|
||||
page_cur_position(rec, block, &cur1);
|
||||
|
||||
if (page_cur_is_before_first(&cur1)) {
|
||||
page_cur_move_to_next(&cur1);
|
||||
if (page_cur_is_before_first(&cur1) && !page_cur_move_to_next(&cur1)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
|
||||
|
@ -1309,6 +1334,9 @@ rtr_page_copy_rec_list_end_no_locks(
|
|||
|
||||
cur_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(buf_block_get_frame(new_block)));
|
||||
if (UNIV_UNLIKELY(!cur_rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
page_cur_position(cur_rec, new_block, &page_cur);
|
||||
|
||||
/* Copy records from the original page to the new page */
|
||||
|
@ -1318,6 +1346,9 @@ rtr_page_copy_rec_list_end_no_locks(
|
|||
|
||||
if (page_rec_is_infimum(cur_rec)) {
|
||||
cur_rec = page_rec_get_next(cur_rec);
|
||||
if (UNIV_UNLIKELY(!cur_rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
|
||||
|
@ -1336,8 +1367,7 @@ rtr_page_copy_rec_list_end_no_locks(
|
|||
goto move_to_prev;
|
||||
} else if (cmp > 0) {
|
||||
/* Skip small recs. */
|
||||
page_cur_move_to_next(&page_cur);
|
||||
cur_rec = page_cur_get_rec(&page_cur);
|
||||
cur_rec = page_cur_move_to_next(&page_cur);
|
||||
} else if (n_core) {
|
||||
if (rec_get_deleted_flag(cur1_rec,
|
||||
dict_table_is_comp(index->table))) {
|
||||
|
@ -1380,7 +1410,9 @@ move_to_prev:
|
|||
rec_move[moved].moved = false;
|
||||
moved++;
|
||||
next:
|
||||
page_cur_move_to_next(&cur1);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
*num_moved = moved;
|
||||
|
@ -1419,10 +1451,15 @@ rtr_page_copy_rec_list_start_no_locks(
|
|||
rec_offs_init(offsets_2);
|
||||
|
||||
page_cur_set_before_first(block, &cur1);
|
||||
page_cur_move_to_next(&cur1);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
cur_rec = page_rec_get_next(
|
||||
page_get_infimum_rec(buf_block_get_frame(new_block)));
|
||||
if (UNIV_UNLIKELY(!cur_rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
page_cur_position(cur_rec, new_block, &page_cur);
|
||||
|
||||
while (page_cur_get_rec(&cur1) != rec) {
|
||||
|
@ -1431,6 +1468,9 @@ rtr_page_copy_rec_list_start_no_locks(
|
|||
|
||||
if (page_rec_is_infimum(cur_rec)) {
|
||||
cur_rec = page_rec_get_next(cur_rec);
|
||||
if (UNIV_UNLIKELY(!cur_rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
|
||||
|
@ -1449,8 +1489,7 @@ rtr_page_copy_rec_list_start_no_locks(
|
|||
goto move_to_prev;
|
||||
} else if (cmp > 0) {
|
||||
/* Skip small recs. */
|
||||
page_cur_move_to_next(&page_cur);
|
||||
cur_rec = page_cur_get_rec(&page_cur);
|
||||
cur_rec = page_cur_move_to_next(&page_cur);
|
||||
} else if (n_core) {
|
||||
if (rec_get_deleted_flag(
|
||||
cur1_rec,
|
||||
|
@ -1472,13 +1511,14 @@ rtr_page_copy_rec_list_start_no_locks(
|
|||
if (page_rec_is_supremum(cur_rec)) {
|
||||
move_to_prev:
|
||||
cur_rec = page_cur_move_to_prev(&page_cur);
|
||||
if (UNIV_UNLIKELY(!cur_rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
} else {
|
||||
cur_rec = page_cur_get_rec(&page_cur);
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(!cur_rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
|
@ -1493,7 +1533,9 @@ move_to_prev:
|
|||
rec_move[moved].moved = false;
|
||||
moved++;
|
||||
next:
|
||||
page_cur_move_to_next(&cur1);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
*num_moved = moved;
|
||||
|
@ -1559,7 +1601,7 @@ rtr_merge_and_update_mbr(
|
|||
rtr_mbr_t new_mbr;
|
||||
|
||||
if (rtr_merge_mbr_changed(cursor, cursor2, offsets, offsets2,
|
||||
&new_mbr)) {
|
||||
&new_mbr)) {
|
||||
rtr_update_mbr_field(cursor, offsets, cursor2, child_page,
|
||||
&new_mbr, NULL, mtr);
|
||||
} else {
|
||||
|
@ -1604,10 +1646,9 @@ rtr_check_same_block(
|
|||
{
|
||||
ulint page_no = childb->page.id().page_no();
|
||||
rec_offs* offsets;
|
||||
rec_t* rec = page_rec_get_next(page_get_infimum_rec(
|
||||
buf_block_get_frame(parentb)));
|
||||
rec_t* rec = page_get_infimum_rec(parentb->page.frame);
|
||||
|
||||
while (!page_rec_is_supremum(rec)) {
|
||||
while ((rec = page_rec_get_next(rec)) && !page_rec_is_supremum(rec)) {
|
||||
offsets = rec_get_offsets(
|
||||
rec, index, NULL, 0, ULINT_UNDEFINED, &heap);
|
||||
|
||||
|
@ -1615,8 +1656,6 @@ rtr_check_same_block(
|
|||
btr_cur_position(index, rec, parentb, cursor);
|
||||
return(true);
|
||||
}
|
||||
|
||||
rec = page_rec_get_next(rec);
|
||||
}
|
||||
|
||||
return(false);
|
||||
|
@ -1826,9 +1865,9 @@ err_exit:
|
|||
|
||||
/* Scan records in root page and calculate area. */
|
||||
double area = 0;
|
||||
for (const rec_t* rec = page_rec_get_next(
|
||||
for (const rec_t* rec = page_rec_get_next_const(
|
||||
page_get_infimum_rec(block->page.frame));
|
||||
!page_rec_is_supremum(rec);
|
||||
rec && !page_rec_is_supremum(rec);
|
||||
rec = page_rec_get_next_const(rec)) {
|
||||
rtr_mbr_t mbr;
|
||||
double rec_area;
|
||||
|
|
|
@ -301,18 +301,17 @@ rtr_pcur_getnext_from_path(
|
|||
page_cursor->rec = NULL;
|
||||
|
||||
if (mode == PAGE_CUR_RTREE_LOCATE) {
|
||||
if (level == target_level && level == 0) {
|
||||
ulint low_match;
|
||||
if (target_level == 0 && level == 0) {
|
||||
ulint low_match = 0, up_match = 0;
|
||||
|
||||
found = false;
|
||||
|
||||
low_match = page_cur_search(
|
||||
block, index, tuple,
|
||||
PAGE_CUR_LE,
|
||||
btr_cur_get_page_cur(btr_cur));
|
||||
|
||||
if (low_match == dtuple_get_n_fields_cmp(
|
||||
tuple)) {
|
||||
if (!page_cur_search_with_match(
|
||||
block, index, tuple, PAGE_CUR_LE,
|
||||
&up_match, &low_match,
|
||||
btr_cur_get_page_cur(btr_cur), nullptr)
|
||||
&& low_match
|
||||
== dtuple_get_n_fields_cmp(tuple)) {
|
||||
rec_t* rec = btr_cur_get_rec(btr_cur);
|
||||
|
||||
if (!rec_get_deleted_flag(rec,
|
||||
|
@ -803,6 +802,9 @@ rtr_page_get_father_block(
|
|||
{
|
||||
rec_t* rec = page_rec_get_next(
|
||||
page_get_infimum_rec(buf_block_get_frame(block)));
|
||||
if (!rec) {
|
||||
return nullptr;
|
||||
}
|
||||
btr_cur_position(index, rec, block, cursor);
|
||||
|
||||
return(rtr_page_get_father_node_ptr(offsets, heap, sea_cur,
|
||||
|
@ -1238,11 +1240,14 @@ rtr_cur_restore_position(
|
|||
ut_ad(r_cursor == node->cursor);
|
||||
|
||||
search_again:
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
block = buf_page_get_gen(
|
||||
page_id_t(index->table->space_id, page_no),
|
||||
zip_size, RW_X_LATCH, NULL, BUF_GET, mtr);
|
||||
|
||||
if (!block) {
|
||||
corrupted:
|
||||
ret = false;
|
||||
goto func_exit;
|
||||
}
|
||||
|
@ -1251,8 +1256,13 @@ search_again:
|
|||
page = buf_block_get_frame(block);
|
||||
page_ssn = page_get_ssn_id(page);
|
||||
|
||||
if (page_cur_search(block, index, tuple, PAGE_CUR_LE, page_cursor)
|
||||
== r_cursor->old_n_fields) {
|
||||
if (page_cur_search_with_match(block, index, tuple, PAGE_CUR_LE,
|
||||
&up_match, &low_match, page_cursor,
|
||||
nullptr)) {
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if (low_match == r_cursor->old_n_fields) {
|
||||
const rec_t* rec;
|
||||
const rec_offs* offsets1;
|
||||
const rec_offs* offsets2;
|
||||
|
@ -1609,13 +1619,20 @@ rtr_cur_search_with_match(
|
|||
mode = PAGE_CUR_WITHIN;
|
||||
}
|
||||
|
||||
rec = page_dir_slot_get_rec(page_dir_get_nth_slot(page, 0));
|
||||
rec = page_dir_slot_get_rec_validate(page_dir_get_nth_slot(page, 0));
|
||||
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
last_rec = rec;
|
||||
best_rec = rec;
|
||||
|
||||
if (page_rec_is_infimum(rec)) {
|
||||
rec = page_rec_get_next_const(rec);
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check insert tuple size is larger than first rec, and try to
|
||||
|
@ -1813,7 +1830,7 @@ rtr_cur_search_with_match(
|
|||
}
|
||||
|
||||
/* All records on page are searched */
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
if (rec && page_rec_is_supremum(rec)) {
|
||||
if (!n_core) {
|
||||
if (!found) {
|
||||
/* No match case, if it is for insertion,
|
||||
|
|
|
@ -2132,11 +2132,14 @@ non_empty:
|
|||
return false;
|
||||
}
|
||||
rec= page_rec_get_next(btr_pcur_get_rec(&pcur));
|
||||
if (UNIV_UNLIKELY(!rec))
|
||||
goto non_empty;
|
||||
if (rec_is_metadata(rec, *clust_index))
|
||||
btr_pcur_get_page_cur(&pcur)->rec= rec;
|
||||
scan_leaf:
|
||||
cur= btr_pcur_get_page_cur(&pcur);
|
||||
page_cur_move_to_next(cur);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(cur)))
|
||||
goto non_empty;
|
||||
next_page:
|
||||
if (next_page)
|
||||
{
|
||||
|
@ -2154,7 +2157,8 @@ next_page:
|
|||
goto non_empty;
|
||||
btr_leaf_page_release(page_cur_get_block(cur), BTR_SEARCH_LEAF, &mtr);
|
||||
page_cur_set_before_first(block, cur);
|
||||
page_cur_move_to_next(cur);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(cur)))
|
||||
goto non_empty;
|
||||
}
|
||||
|
||||
rec= page_cur_get_rec(cur);
|
||||
|
@ -6029,13 +6033,17 @@ func_exit:
|
|||
return false;
|
||||
}
|
||||
ut_ad(btr_pcur_is_before_first_on_page(&pcur));
|
||||
btr_pcur_move_to_next_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));
|
||||
ut_ad(!buf_block_get_page_zip(block));
|
||||
const rec_t* rec = btr_pcur_get_rec(&pcur);
|
||||
const rec_t* rec = btr_pcur_move_to_next_on_page(&pcur);
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
que_thr_t* thr = pars_complete_graph_for_exec(
|
||||
NULL, trx, ctx->heap, NULL);
|
||||
const bool is_root = block->page.id().page_no() == index->page;
|
||||
|
|
|
@ -929,7 +929,7 @@ ibuf_page_low(
|
|||
zip_size, RW_NO_LATCH, nullptr, BUF_GET, &local_mtr);
|
||||
|
||||
ret = block
|
||||
&& ibuf_bitmap_page_get_bits_low(
|
||||
&& ibuf_bitmap_page_get_bits_low(
|
||||
block->page.frame, page_id, zip_size,
|
||||
MTR_MEMO_BUF_FIX, &local_mtr, IBUF_BITMAP_IBUF);
|
||||
|
||||
|
@ -2047,7 +2047,7 @@ corruption:
|
|||
|
||||
if (page_rec_is_infimum(rec)) {
|
||||
rec = page_rec_get_next_const(rec);
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
if (!rec || page_rec_is_supremum(rec)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -2101,7 +2101,7 @@ corruption:
|
|||
sum_volumes = 0;
|
||||
volume_for_page = 0;
|
||||
|
||||
while (*n_stored < limit) {
|
||||
while (*n_stored < limit && rec) {
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
/* When no more records available, mark this with
|
||||
another 'impossible' pair of space id, page no */
|
||||
|
@ -2861,10 +2861,10 @@ corruption:
|
|||
static_assert(FIL_PAGE_NEXT % 4 == 0, "alignment");
|
||||
static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment");
|
||||
|
||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(prev_page + FIL_PAGE_NEXT,
|
||||
page + FIL_PAGE_OFFSET, 4))) {
|
||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(prev_page + FIL_PAGE_NEXT,
|
||||
page + FIL_PAGE_OFFSET, 4))) {
|
||||
return srv_page_size;
|
||||
}
|
||||
}
|
||||
|
||||
rec = page_rec_get_prev_const(page_get_supremum_rec(prev_page));
|
||||
|
||||
|
@ -2908,6 +2908,9 @@ count_later:
|
|||
|
||||
for (; !page_rec_is_supremum(rec);
|
||||
rec = page_rec_get_next_const(rec)) {
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return srv_page_size;
|
||||
}
|
||||
if (page_no != ibuf_rec_get_page_no(mtr, rec)
|
||||
|| space != ibuf_rec_get_space(mtr, rec)) {
|
||||
|
||||
|
@ -2940,24 +2943,22 @@ count_later:
|
|||
static_assert(FIL_PAGE_PREV % 4 == 0, "alignment");
|
||||
static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment");
|
||||
|
||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(next_page + FIL_PAGE_PREV,
|
||||
page + FIL_PAGE_OFFSET, 4))) {
|
||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(next_page + FIL_PAGE_PREV,
|
||||
page + FIL_PAGE_OFFSET, 4))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rec = page_get_infimum_rec(next_page);
|
||||
rec = page_rec_get_next_const(rec);
|
||||
|
||||
for (;; rec = page_rec_get_next_const(rec)) {
|
||||
ut_ad(page_align(rec) == next_page);
|
||||
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
|
||||
for (; ; rec = page_rec_get_next_const(rec)) {
|
||||
if (!rec || page_rec_is_supremum(rec)) {
|
||||
/* We give up */
|
||||
|
||||
return(srv_page_size);
|
||||
}
|
||||
|
||||
ut_ad(page_align(rec) == next_page);
|
||||
|
||||
if (page_no != ibuf_rec_get_page_no(mtr, rec)
|
||||
|| space != ibuf_rec_get_space(mtr, rec)) {
|
||||
|
||||
|
@ -3697,7 +3698,6 @@ ibuf_insert_to_index_page(
|
|||
mtr_t* mtr) /*!< in: mtr */
|
||||
{
|
||||
page_cur_t page_cur;
|
||||
ulint low_match;
|
||||
page_t* page = buf_block_get_frame(block);
|
||||
rec_t* rec;
|
||||
rec_offs* offsets;
|
||||
|
@ -3726,7 +3726,7 @@ ibuf_insert_to_index_page(
|
|||
|
||||
rec = page_rec_get_next(page_get_infimum_rec(page));
|
||||
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
if (!rec || page_rec_is_supremum(rec)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
|
@ -3734,8 +3734,15 @@ ibuf_insert_to_index_page(
|
|||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
if (page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
|
||||
&up_match, &low_match, &page_cur,
|
||||
nullptr)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
dberr_t err = DB_SUCCESS;
|
||||
low_match = page_cur_search(block, index, entry, &page_cur);
|
||||
|
||||
heap = mem_heap_create(
|
||||
sizeof(upd_t)
|
||||
|
@ -3824,7 +3831,7 @@ ibuf_insert_to_index_page(
|
|||
}
|
||||
} else {
|
||||
offsets = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
err = ibuf_insert_to_index_page_low(entry, block, index,
|
||||
&offsets, heap, mtr, &page_cur);
|
||||
|
@ -3847,14 +3854,15 @@ ibuf_set_del_mark(
|
|||
mtr_t* mtr) /*!< in: mtr */
|
||||
{
|
||||
page_cur_t page_cur;
|
||||
ulint low_match;
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
ut_ad(ibuf_inside(mtr));
|
||||
ut_ad(dtuple_check_typed(entry));
|
||||
|
||||
low_match = page_cur_search(block, index, entry, &page_cur);
|
||||
|
||||
if (low_match == dtuple_get_n_fields(entry)) {
|
||||
if (!page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
|
||||
&up_match, &low_match, &page_cur,
|
||||
nullptr)
|
||||
&& low_match == dtuple_get_n_fields(entry)) {
|
||||
rec_t* rec = page_cur_get_rec(&page_cur);
|
||||
|
||||
/* Delete mark the old index record. According to a
|
||||
|
@ -3903,16 +3911,17 @@ ibuf_delete(
|
|||
before latching any further pages */
|
||||
{
|
||||
page_cur_t page_cur;
|
||||
ulint low_match;
|
||||
ulint up_match = 0, low_match = 0;
|
||||
|
||||
ut_ad(ibuf_inside(mtr));
|
||||
ut_ad(dtuple_check_typed(entry));
|
||||
ut_ad(!index->is_spatial());
|
||||
ut_ad(!index->is_clust());
|
||||
|
||||
low_match = page_cur_search(block, index, entry, &page_cur);
|
||||
|
||||
if (low_match == dtuple_get_n_fields(entry)) {
|
||||
if (!page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
|
||||
&up_match, &low_match, &page_cur,
|
||||
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);
|
||||
|
@ -3976,8 +3985,6 @@ ibuf_delete(
|
|||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
} else {
|
||||
/* The record must have been purged already. */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4016,9 +4023,6 @@ ibuf_restore_pos(
|
|||
rec_print_old(stderr, btr_pcur_get_rec(pcur));
|
||||
rec_print_old(stderr, pcur->old_rec);
|
||||
dtuple_print(stderr, search_tuple);
|
||||
|
||||
rec_print_old(stderr,
|
||||
page_rec_get_next(btr_pcur_get_rec(pcur)));
|
||||
}
|
||||
|
||||
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
|
||||
|
@ -4644,7 +4648,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 = buf_block_get_frame(block);
|
||||
ut_ad(buf_is_zeroes(span<const byte>(
|
||||
page,
|
||||
physical_size)));
|
||||
|
|
|
@ -222,7 +222,7 @@ It is assumed that mtr holds an x-latch on the page. The operation does
|
|||
not succeed if there is too little space on the page. If there is just
|
||||
one record on the page, the insert will always succeed; this is to
|
||||
prevent trying to split a page with just one record.
|
||||
@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
|
||||
@return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL, or error number */
|
||||
dberr_t
|
||||
btr_cur_optimistic_insert(
|
||||
/*======================*/
|
||||
|
|
|
@ -324,10 +324,11 @@ static inline bool btr_pcur_is_before_first_in_tree(btr_pcur_t* cursor);
|
|||
Checks if the persistent cursor is after the last user record in
|
||||
the index tree. */
|
||||
static inline bool btr_pcur_is_after_last_in_tree(btr_pcur_t* cursor);
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||
/*********************************************************//**
|
||||
Moves the persistent cursor to the next record on the same page. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
rec_t*
|
||||
btr_pcur_move_to_next_on_page(
|
||||
/*==========================*/
|
||||
btr_pcur_t* cursor);/*!< in/out: persistent cursor */
|
||||
|
@ -513,8 +514,7 @@ btr_pcur_open_on_user_rec(
|
|||
return DB_SUCCESS;
|
||||
if (dberr_t err= btr_pcur_move_to_next_page(cursor, mtr))
|
||||
return err;
|
||||
btr_pcur_move_to_next_on_page(cursor);
|
||||
return DB_SUCCESS;
|
||||
return btr_pcur_move_to_next_on_page(cursor) ? DB_SUCCESS : DB_CORRUPTION;
|
||||
}
|
||||
|
||||
#include "btr0pcur.inl"
|
||||
|
|
|
@ -155,7 +155,7 @@ static inline bool btr_pcur_is_after_last_in_tree(btr_pcur_t* cursor)
|
|||
/*********************************************************//**
|
||||
Moves the persistent cursor to the next record on the same page. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
rec_t*
|
||||
btr_pcur_move_to_next_on_page(
|
||||
/*==========================*/
|
||||
btr_pcur_t* cursor) /*!< in/out: persistent cursor */
|
||||
|
@ -163,9 +163,8 @@ btr_pcur_move_to_next_on_page(
|
|||
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
|
||||
|
||||
cursor->old_stored = false;
|
||||
return page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
|
@ -204,8 +203,8 @@ loop:
|
|||
|| btr_pcur_move_to_next_page(cursor, mtr) != DB_SUCCESS) {
|
||||
return(FALSE);
|
||||
}
|
||||
} else {
|
||||
btr_pcur_move_to_next_on_page(cursor);
|
||||
} else if (UNIV_UNLIKELY(!btr_pcur_move_to_next_on_page(cursor))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (btr_pcur_is_on_user_rec(cursor)) {
|
||||
|
@ -228,20 +227,16 @@ btr_pcur_move_to_next(
|
|||
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);
|
||||
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
cursor->old_stored = false;
|
||||
cursor->old_stored= false;
|
||||
|
||||
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 {
|
||||
btr_pcur_move_to_next_on_page(cursor);
|
||||
}
|
||||
return(TRUE);
|
||||
if (btr_pcur_is_after_last_on_page(cursor))
|
||||
return !btr_pcur_is_after_last_in_tree(cursor) &&
|
||||
btr_pcur_move_to_next_page(cursor, mtr) == DB_SUCCESS;
|
||||
else
|
||||
return !!btr_pcur_move_to_next_on_page(cursor);
|
||||
}
|
||||
|
||||
/**************************************************************//**
|
||||
|
|
|
@ -57,6 +57,9 @@ rtr_page_cal_mbr(
|
|||
page = buf_block_get_frame(block);
|
||||
|
||||
rec = page_rec_get_next(page_get_infimum_rec(page));
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return;
|
||||
}
|
||||
offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page)
|
||||
? index->n_fields : 0,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
|
|
@ -110,21 +110,6 @@ page_cur_position(
|
|||
const buf_block_t* block, /*!< in: buffer block containing
|
||||
the record */
|
||||
page_cur_t* cur); /*!< out: page cursor */
|
||||
/**********************************************************//**
|
||||
Moves the cursor to the next record on page. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
page_cur_move_to_next(
|
||||
/*==================*/
|
||||
page_cur_t* cur); /*!< in/out: cursor; must not be after last */
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||
/**********************************************************//**
|
||||
Moves the cursor to the previous record on page. */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_cur_move_to_prev(
|
||||
/*==================*/
|
||||
page_cur_t* cur); /*!< in/out: cursor; not before first */
|
||||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor. Returns pointer to inserted record if
|
||||
|
@ -166,20 +151,20 @@ page_cur_insert_rec_low(
|
|||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor on a compressed and uncompressed
|
||||
page. Returns pointer to inserted record if succeed, i.e.,
|
||||
enough space available, NULL otherwise.
|
||||
The cursor stays at the same position.
|
||||
page.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
@return pointer to inserted record
|
||||
@return nullptr on failure */
|
||||
rec_t*
|
||||
page_cur_insert_rec_zip(
|
||||
/*====================*/
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor,
|
||||
logical position unchanged */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
const rec_t* rec, /*!< in: pointer to a physical record */
|
||||
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
|
||||
|
@ -248,39 +233,10 @@ page_cur_delete_rec() for a ROW_FORMAT=COMPACT or DYNAMIC page.
|
|||
bool page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
|
||||
size_t hdr_size, size_t data_size);
|
||||
|
||||
/** Search the right position for a page cursor.
|
||||
@param[in] block buffer block
|
||||
@param[in] index index tree
|
||||
@param[in] tuple data tuple
|
||||
@param[in] mode PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE
|
||||
@param[out] cursor page cursor
|
||||
@return number of matched fields on the left */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
page_cur_search(
|
||||
const buf_block_t* block,
|
||||
const dict_index_t* index,
|
||||
const dtuple_t* tuple,
|
||||
page_cur_mode_t mode,
|
||||
page_cur_t* cursor);
|
||||
|
||||
/** Search the right position for a page cursor.
|
||||
@param[in] block buffer block
|
||||
@param[in] index index tree
|
||||
@param[in] tuple data tuple
|
||||
@param[out] cursor page cursor
|
||||
@return number of matched fields on the left */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
page_cur_search(
|
||||
const buf_block_t* block,
|
||||
const dict_index_t* index,
|
||||
const dtuple_t* tuple,
|
||||
page_cur_t* cursor);
|
||||
|
||||
MY_ATTRIBUTE((warn_unused_result))
|
||||
/****************************************************************//**
|
||||
Searches the right position for a page cursor. */
|
||||
void
|
||||
bool
|
||||
page_cur_search_with_match(
|
||||
/*=======================*/
|
||||
const buf_block_t* block, /*!< in: buffer block */
|
||||
|
@ -298,6 +254,7 @@ page_cur_search_with_match(
|
|||
page_cur_t* cursor, /*!< out: page cursor */
|
||||
rtr_info_t* rtr_info);/*!< in/out: rtree search stack */
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
MY_ATTRIBUTE((warn_unused_result))
|
||||
/** Search the right position for a page cursor.
|
||||
@param[in] block buffer block
|
||||
@param[in] index index tree
|
||||
|
@ -312,7 +269,7 @@ lower limit record
|
|||
@param[in,out] ilow_matched_bytes already matched bytes in the
|
||||
first partially matched field in the lower limit record
|
||||
@param[out] cursor page cursor */
|
||||
void
|
||||
bool
|
||||
page_cur_search_with_match_bytes(
|
||||
const buf_block_t* block,
|
||||
const dict_index_t* index,
|
||||
|
@ -342,6 +299,19 @@ struct page_cur_t{
|
|||
buf_block_t* block; /*!< pointer to the block containing rec */
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#include "page0cur.inl"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2015, 2021, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2022, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -149,75 +149,6 @@ page_cur_position(
|
|||
cur->block = (buf_block_t*) block;
|
||||
}
|
||||
|
||||
/**********************************************************//**
|
||||
Moves the cursor to the next record on page. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
page_cur_move_to_next(
|
||||
/*==================*/
|
||||
page_cur_t* cur) /*!< in/out: cursor; must not be after last */
|
||||
{
|
||||
ut_ad(!page_cur_is_after_last(cur));
|
||||
|
||||
cur->rec = page_rec_get_next(cur->rec);
|
||||
}
|
||||
|
||||
/**********************************************************//**
|
||||
Moves the cursor to the previous record on page. */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_cur_move_to_prev(
|
||||
/*==================*/
|
||||
page_cur_t* cur) /*!< in/out: page cursor, not before first */
|
||||
{
|
||||
ut_ad(!page_cur_is_before_first(cur));
|
||||
|
||||
return cur->rec = page_rec_get_prev(cur->rec);
|
||||
}
|
||||
|
||||
/** Search the right position for a page cursor.
|
||||
@param[in] block buffer block
|
||||
@param[in] index index tree
|
||||
@param[in] tuple data tuple
|
||||
@param[in] mode PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE
|
||||
@param[out] cursor page cursor
|
||||
@return number of matched fields on the left */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
page_cur_search(
|
||||
const buf_block_t* block,
|
||||
const dict_index_t* index,
|
||||
const dtuple_t* tuple,
|
||||
page_cur_mode_t mode,
|
||||
page_cur_t* cursor)
|
||||
{
|
||||
ulint low_match = 0;
|
||||
ulint up_match = 0;
|
||||
|
||||
ut_ad(dtuple_check_typed(tuple));
|
||||
|
||||
page_cur_search_with_match(block, index, tuple, mode,
|
||||
&up_match, &low_match, cursor, NULL);
|
||||
return(low_match);
|
||||
}
|
||||
|
||||
/** Search the right position for a page cursor.
|
||||
@param[in] block buffer block
|
||||
@param[in] index index tree
|
||||
@param[in] tuple data tuple
|
||||
@param[out] cursor page cursor
|
||||
@return number of matched fields on the left */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
page_cur_search(
|
||||
const buf_block_t* block,
|
||||
const dict_index_t* index,
|
||||
const dtuple_t* tuple,
|
||||
page_cur_t* cursor)
|
||||
{
|
||||
return(page_cur_search(block, index, tuple, PAGE_CUR_LE, cursor));
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor. Returns pointer to inserted record if
|
||||
succeed, i.e., enough space available, NULL otherwise. The cursor stays at
|
||||
|
|
|
@ -534,7 +534,8 @@ inline void page_header_reset_last_insert(buf_block_t *block, mtr_t *mtr)
|
|||
/************************************************************//**
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
@return nth record
|
||||
@retval nullptr on corrupted page */
|
||||
const rec_t*
|
||||
page_rec_get_nth_const(
|
||||
/*===================*/
|
||||
|
@ -544,14 +545,12 @@ page_rec_get_nth_const(
|
|||
/************************************************************//**
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_rec_get_nth(
|
||||
/*=============*/
|
||||
page_t* page, /*< in: page */
|
||||
ulint nth) /*!< in: nth record */
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
@return nth record
|
||||
@retval nullptr on corrupted page */
|
||||
inline rec_t *page_rec_get_nth(page_t* page, ulint nth)
|
||||
{
|
||||
return const_cast<rec_t*>(page_rec_get_nth_const(page, nth));
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Returns the middle record of the records on the page. If there is an
|
||||
|
@ -592,15 +591,11 @@ page_get_n_recs(
|
|||
/*============*/
|
||||
const page_t* page); /*!< in: index page */
|
||||
|
||||
/***************************************************************//**
|
||||
Returns the number of records before the given record in chain.
|
||||
The number includes infimum and supremum records.
|
||||
This is the inverse function of page_rec_get_nth().
|
||||
@return number of records */
|
||||
ulint
|
||||
page_rec_get_n_recs_before(
|
||||
/*=======================*/
|
||||
const rec_t* rec); /*!< in: the physical record */
|
||||
/** Return the number of preceding records in an 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);
|
||||
/*************************************************************//**
|
||||
Gets the number of records in the heap.
|
||||
@return number of user records */
|
||||
|
@ -649,6 +644,23 @@ inline const rec_t *page_dir_slot_get_rec(const page_dir_slot_t *slot)
|
|||
{
|
||||
return page_dir_slot_get_rec(const_cast<rec_t*>(slot));
|
||||
}
|
||||
|
||||
inline rec_t *page_dir_slot_get_rec_validate(page_dir_slot_t *slot)
|
||||
{
|
||||
const size_t s= mach_read_from_2(my_assume_aligned<2>(slot));
|
||||
page_t *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)
|
||||
{
|
||||
return page_dir_slot_get_rec_validate(const_cast<rec_t*>(slot));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************//**
|
||||
Gets the number of records owned by a directory slot.
|
||||
@return number of records */
|
||||
|
@ -753,20 +765,9 @@ page_rec_get_next_const(
|
|||
/*====================*/
|
||||
const rec_t* rec); /*!< in: pointer to record */
|
||||
/************************************************************//**
|
||||
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 */
|
||||
UNIV_INLINE
|
||||
const rec_t*
|
||||
page_rec_get_next_non_del_marked(
|
||||
/*=============================*/
|
||||
const rec_t* rec); /*!< in: pointer to record */
|
||||
/************************************************************//**
|
||||
Gets the pointer to the previous record.
|
||||
@return pointer to previous record
|
||||
@retval nullptr on error */
|
||||
UNIV_INLINE
|
||||
const rec_t*
|
||||
page_rec_get_prev_const(
|
||||
/*====================*/
|
||||
|
@ -815,22 +816,6 @@ page_rec_is_last(
|
|||
const page_t* page) /*!< in: page */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/************************************************************//**
|
||||
true if distance between the records (measured in number of times we have to
|
||||
move to the next record) is at most the specified value
|
||||
@param[in] left_rec lefter record
|
||||
@param[in] right_rec righter record
|
||||
@param[in] val specified value to compare
|
||||
@return true if the distance is smaller than the value */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
page_rec_distance_is_at_most(
|
||||
/*=========================*/
|
||||
const rec_t* left_rec,
|
||||
const rec_t* right_rec,
|
||||
ulint val)
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/************************************************************//**
|
||||
true if the record is the second last user record on a page.
|
||||
@return true if the second last user record */
|
||||
|
@ -1129,9 +1114,7 @@ page_find_rec_with_heap_no(
|
|||
@param[in] page index tree leaf page
|
||||
@return the last record, not delete-marked
|
||||
@retval infimum record if all records are delete-marked */
|
||||
const rec_t*
|
||||
page_find_rec_max_not_deleted(
|
||||
const page_t* page);
|
||||
const rec_t *page_find_rec_max_not_deleted(const page_t *page);
|
||||
|
||||
#endif /* !UNIV_INNOCHECKSUM */
|
||||
|
||||
|
|
|
@ -202,10 +202,10 @@ page_rec_is_second(
|
|||
const rec_t* rec, /*!< in: record */
|
||||
const page_t* page) /*!< in: page */
|
||||
{
|
||||
ut_ad(page_get_n_recs(page) > 1);
|
||||
|
||||
return(page_rec_get_next_const(
|
||||
page_rec_get_next_const(page_get_infimum_rec(page))) == rec);
|
||||
ut_ad(page_get_n_recs(page) > 1);
|
||||
if (const rec_t *first= page_rec_get_next_const(page_get_infimum_rec(page)))
|
||||
return page_rec_get_next_const(first) == rec;
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
@ -223,26 +223,6 @@ page_rec_is_last(
|
|||
return(page_rec_get_next_const(rec) == page_get_supremum_rec(page));
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
true if distance between the records (measured in number of times we have to
|
||||
move to the next record) is at most the specified value */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
page_rec_distance_is_at_most(
|
||||
/*=========================*/
|
||||
const rec_t* left_rec,
|
||||
const rec_t* right_rec,
|
||||
ulint val)
|
||||
{
|
||||
for (ulint i = 0; i <= val; i++) {
|
||||
if (left_rec == right_rec) {
|
||||
return (true);
|
||||
}
|
||||
left_rec = page_rec_get_next_const(left_rec);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
true if the record is the second last user record on a page.
|
||||
@return true if the second last user record */
|
||||
|
@ -253,25 +233,12 @@ page_rec_is_second_last(
|
|||
const rec_t* rec, /*!< in: record */
|
||||
const page_t* page) /*!< in: page */
|
||||
{
|
||||
ut_ad(page_get_n_recs(page) > 1);
|
||||
ut_ad(!page_rec_is_last(rec, page));
|
||||
ut_ad(page_get_n_recs(page) > 1);
|
||||
ut_ad(!page_rec_is_last(rec, page));
|
||||
|
||||
return(page_rec_get_next_const(
|
||||
page_rec_get_next_const(rec)) == page_get_supremum_rec(page));
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_rec_get_nth(
|
||||
/*=============*/
|
||||
page_t* page, /*!< in: page */
|
||||
ulint nth) /*!< in: nth record */
|
||||
{
|
||||
return((rec_t*) page_rec_get_nth_const(page, nth));
|
||||
if (const rec_t *next= page_rec_get_next_const(rec))
|
||||
return page_rec_is_supremum(page_rec_get_next_const(next));
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
@ -421,36 +388,19 @@ page_rec_get_next_low(
|
|||
const rec_t* rec, /*!< in: pointer to record */
|
||||
ulint comp) /*!< in: nonzero=compact page layout */
|
||||
{
|
||||
ulint offs;
|
||||
const page_t* page;
|
||||
|
||||
ut_ad(page_rec_check(rec));
|
||||
|
||||
page = page_align(rec);
|
||||
|
||||
offs = rec_get_next_offs(rec, comp);
|
||||
|
||||
if (offs >= srv_page_size) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Next record offset is nonsensical %lu"
|
||||
" in record at offset %lu\n"
|
||||
"InnoDB: rec address %p, space id %lu, page %lu\n",
|
||||
(ulong) offs, (ulong) page_offset(rec),
|
||||
(void*) rec,
|
||||
(ulong) page_get_space_id(page),
|
||||
(ulong) page_get_page_no(page));
|
||||
ut_error;
|
||||
} else if (offs == 0) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
@ -476,78 +426,6 @@ page_rec_get_next_const(
|
|||
{
|
||||
return(page_rec_get_next_low(rec, page_rec_is_comp(rec)));
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
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 */
|
||||
UNIV_INLINE
|
||||
const rec_t*
|
||||
page_rec_get_next_non_del_marked(
|
||||
/*=============================*/
|
||||
const rec_t* rec) /*!< in: pointer to record */
|
||||
{
|
||||
const rec_t* r;
|
||||
ulint page_is_compact = page_rec_is_comp(rec);
|
||||
|
||||
for (r = page_rec_get_next_const(rec);
|
||||
!page_rec_is_supremum(r)
|
||||
&& rec_get_deleted_flag(r, page_is_compact);
|
||||
r = page_rec_get_next_const(r)) {
|
||||
/* noop */
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Gets the pointer to the previous record.
|
||||
@return pointer to previous record
|
||||
@retval nullptr on error */
|
||||
UNIV_INLINE
|
||||
const rec_t*
|
||||
page_rec_get_prev_const(
|
||||
/*====================*/
|
||||
const rec_t* rec) /*!< in: pointer to record, must not be page
|
||||
infimum */
|
||||
{
|
||||
const page_dir_slot_t* slot;
|
||||
ulint slot_no;
|
||||
const rec_t* rec2;
|
||||
const rec_t* prev_rec = NULL;
|
||||
const page_t* page;
|
||||
|
||||
ut_ad(page_rec_check(rec));
|
||||
|
||||
page = page_align(rec);
|
||||
|
||||
ut_ad(!page_rec_is_infimum(rec));
|
||||
|
||||
slot_no = page_dir_find_owner_slot(rec);
|
||||
|
||||
if (UNIV_UNLIKELY(!slot_no || slot_no == ULINT_UNDEFINED)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slot = page_dir_get_nth_slot(page, slot_no - 1);
|
||||
|
||||
rec2 = page_dir_slot_get_rec(slot);
|
||||
|
||||
if (page_is_comp(page)) {
|
||||
while (rec2 && rec != rec2) {
|
||||
prev_rec = rec2;
|
||||
rec2 = page_rec_get_next_low(rec2, TRUE);
|
||||
}
|
||||
} else {
|
||||
while (rec2 && rec != rec2) {
|
||||
prev_rec = rec2;
|
||||
rec2 = page_rec_get_next_low(rec2, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return(prev_rec);
|
||||
}
|
||||
#endif /* UNIV_INNOCHECKSUM */
|
||||
|
||||
/************************************************************//**
|
||||
|
|
|
@ -141,28 +141,7 @@ constexpr rec_offs REC_OFFS_EXTERNAL= REC_OFFS_COMPACT >> 1;
|
|||
/** Default value flag in offsets returned by rec_get_offsets() */
|
||||
constexpr rec_offs REC_OFFS_DEFAULT= REC_OFFS_COMPACT >> 2;
|
||||
constexpr rec_offs REC_OFFS_MASK= REC_OFFS_DEFAULT - 1;
|
||||
/******************************************************//**
|
||||
The following function is used to get the pointer of the next chained record
|
||||
on the same page.
|
||||
@return pointer to the next chained record, or NULL if none */
|
||||
UNIV_INLINE
|
||||
const rec_t*
|
||||
rec_get_next_ptr_const(
|
||||
/*===================*/
|
||||
const rec_t* rec, /*!< in: physical record */
|
||||
ulint comp) /*!< in: nonzero=compact page format */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
/******************************************************//**
|
||||
The following function is used to get the pointer of the next chained record
|
||||
on the same page.
|
||||
@return pointer to the next chained record, or NULL if none */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
rec_get_next_ptr(
|
||||
/*=============*/
|
||||
rec_t* rec, /*!< in: physical record */
|
||||
ulint comp) /*!< in: nonzero=compact page format */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/******************************************************//**
|
||||
The following function is used to get the offset of the
|
||||
next chained record on the same page.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -203,76 +203,6 @@ rec_set_bit_field_2(
|
|||
| (val << shift));
|
||||
}
|
||||
|
||||
/******************************************************//**
|
||||
The following function is used to get the pointer of the next chained record
|
||||
on the same page.
|
||||
@return pointer to the next chained record, or NULL if none */
|
||||
UNIV_INLINE
|
||||
const rec_t*
|
||||
rec_get_next_ptr_const(
|
||||
/*===================*/
|
||||
const rec_t* rec, /*!< in: physical record */
|
||||
ulint comp) /*!< in: nonzero=compact page format */
|
||||
{
|
||||
ulint field_value;
|
||||
|
||||
compile_time_assert(REC_NEXT_MASK == 0xFFFFUL);
|
||||
compile_time_assert(REC_NEXT_SHIFT == 0);
|
||||
|
||||
field_value = mach_read_from_2(rec - REC_NEXT);
|
||||
|
||||
if (field_value == 0) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (comp) {
|
||||
#if UNIV_PAGE_SIZE_MAX <= 32768
|
||||
/* Note that for 64 KiB pages, field_value can 'wrap around'
|
||||
and the debug assertion is not valid */
|
||||
|
||||
/* In the following assertion, field_value is interpreted
|
||||
as signed 16-bit integer in 2's complement arithmetics.
|
||||
If all platforms defined int16_t in the standard headers,
|
||||
the expression could be written simpler as
|
||||
(int16_t) field_value + ut_align_offset(...) < srv_page_size
|
||||
*/
|
||||
ut_ad((field_value >= 32768
|
||||
? field_value - 65536
|
||||
: field_value)
|
||||
+ ut_align_offset(rec, srv_page_size)
|
||||
< srv_page_size);
|
||||
#endif
|
||||
/* There must be at least REC_N_NEW_EXTRA_BYTES + 1
|
||||
between each record. */
|
||||
ut_ad((field_value > REC_N_NEW_EXTRA_BYTES
|
||||
&& field_value < 32768)
|
||||
|| field_value < (uint16) -REC_N_NEW_EXTRA_BYTES);
|
||||
|
||||
return((byte*) ut_align_down(rec, srv_page_size)
|
||||
+ ut_align_offset(rec + field_value, srv_page_size));
|
||||
} else {
|
||||
ut_ad(field_value < srv_page_size);
|
||||
|
||||
return((byte*) ut_align_down(rec, srv_page_size)
|
||||
+ field_value);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************//**
|
||||
The following function is used to get the pointer of the next chained record
|
||||
on the same page.
|
||||
@return pointer to the next chained record, or NULL if none */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
rec_get_next_ptr(
|
||||
/*=============*/
|
||||
rec_t* rec, /*!< in: physical record */
|
||||
ulint comp) /*!< in: nonzero=compact page format */
|
||||
{
|
||||
return(const_cast<rec_t*>(rec_get_next_ptr_const(rec, comp)));
|
||||
}
|
||||
|
||||
/******************************************************//**
|
||||
The following function is used to get the offset of the next chained record
|
||||
on the same page.
|
||||
|
|
|
@ -2378,10 +2378,12 @@ lock_move_reorganize_page(
|
|||
|
||||
lock_trx->mutex_unlock();
|
||||
|
||||
if (new_heap_no == PAGE_HEAP_NO_SUPREMUM)
|
||||
if (!rec1 || !rec2)
|
||||
{
|
||||
ut_ad(old_heap_no == PAGE_HEAP_NO_SUPREMUM);
|
||||
break;
|
||||
ut_ad(!rec1 == !rec2);
|
||||
ut_ad(new_heap_no == PAGE_HEAP_NO_SUPREMUM);
|
||||
ut_ad(old_heap_no == PAGE_HEAP_NO_SUPREMUM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2450,6 +2452,12 @@ lock_move_rec_list_end(
|
|||
FALSE);
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(!rec1 || !rec2))
|
||||
{
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy lock requests on user records to new page and
|
||||
reset the lock bits on the old */
|
||||
for (;;)
|
||||
|
@ -2463,28 +2471,37 @@ lock_move_rec_list_end(
|
|||
if (comp)
|
||||
{
|
||||
rec1_heap_no= rec_get_heap_no_new(rec1);
|
||||
if (rec1_heap_no == PAGE_HEAP_NO_SUPREMUM)
|
||||
if (!(rec1= page_rec_get_next_low(rec1, TRUE)))
|
||||
{
|
||||
ut_ad(rec1_heap_no == PAGE_HEAP_NO_SUPREMUM);
|
||||
break;
|
||||
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
ut_d(const rec_t *old1= rec1);
|
||||
rec1_heap_no= rec_get_heap_no_old(rec1);
|
||||
|
||||
if (rec1_heap_no == PAGE_HEAP_NO_SUPREMUM)
|
||||
if (!(rec1= page_rec_get_next_low(rec1, FALSE)))
|
||||
{
|
||||
ut_ad(rec1_heap_no == PAGE_HEAP_NO_SUPREMUM);
|
||||
break;
|
||||
}
|
||||
|
||||
ut_ad(rec_get_data_size_old(old1) == rec_get_data_size_old(rec2));
|
||||
ut_ad(!memcmp(old1, rec2, rec_get_data_size_old(old1)));
|
||||
|
||||
rec2_heap_no= rec_get_heap_no_old(rec2);
|
||||
|
||||
ut_ad(rec_get_data_size_old(rec1) == rec_get_data_size_old(rec2));
|
||||
ut_ad(!memcmp(rec1, rec2, rec_get_data_size_old(rec1)));
|
||||
|
||||
rec1= page_rec_get_next_low(rec1, FALSE);
|
||||
rec2= page_rec_get_next_low(rec2, FALSE);
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(!rec2))
|
||||
{
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
trx_t *lock_trx= lock->trx;
|
||||
lock_trx->mutex_lock();
|
||||
|
||||
|
@ -2577,6 +2594,12 @@ lock_move_rec_list_start(
|
|||
|
||||
while (rec1 != rec)
|
||||
{
|
||||
if (UNIV_UNLIKELY(!rec1 || !rec2))
|
||||
{
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ut_ad(page_rec_is_metadata(rec1) == page_rec_is_metadata(rec2));
|
||||
ut_d(const rec_t* const prev= rec1);
|
||||
|
||||
|
@ -2880,11 +2903,15 @@ void lock_update_merge_left(const buf_block_t& left, const rec_t *orig_pred,
|
|||
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);
|
||||
if (UNIV_UNLIKELY(!left_next_rec))
|
||||
{
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This would likely be too large for a memory transaction. */
|
||||
LockMultiGuard g{lock_sys.rec_hash, l, right};
|
||||
const rec_t *left_next_rec= page_rec_get_next_const(orig_pred);
|
||||
|
||||
if (!page_rec_is_supremum(left_next_rec))
|
||||
{
|
||||
/* Inherit the locks on the supremum of the left page to the
|
||||
|
@ -3031,12 +3058,18 @@ lock_update_insert(
|
|||
|
||||
if (page_rec_is_comp(rec)) {
|
||||
receiver_heap_no = rec_get_heap_no_new(rec);
|
||||
donator_heap_no = rec_get_heap_no_new(
|
||||
page_rec_get_next_low(rec, TRUE));
|
||||
rec = page_rec_get_next_low(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);
|
||||
donator_heap_no = rec_get_heap_no_old(
|
||||
page_rec_get_next_low(rec, FALSE));
|
||||
rec = page_rec_get_next_low(rec, FALSE);
|
||||
if (UNIV_UNLIKELY(!rec)) {
|
||||
return;
|
||||
}
|
||||
donator_heap_no = rec_get_heap_no_old(rec);
|
||||
}
|
||||
|
||||
lock_rec_inherit_to_gap_if_gap_lock(
|
||||
|
@ -4952,13 +4985,15 @@ lock_rec_insert_check_and_lock(
|
|||
ut_ad(page_is_leaf(block->page.frame));
|
||||
ut_ad(!index->table->is_temporary());
|
||||
|
||||
const rec_t *next_rec= page_rec_get_next_const(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);
|
||||
const rec_t *next_rec= page_rec_get_next_const(rec);
|
||||
ulint heap_no= page_rec_get_heap_no(next_rec);
|
||||
const page_id_t id{block->page.id()};
|
||||
ut_ad(!rec_is_metadata(next_rec, *index));
|
||||
|
||||
{
|
||||
LockGuard g{lock_sys.rec_hash, id};
|
||||
|
@ -6333,11 +6368,16 @@ void lock_update_split_and_merge(
|
|||
|
||||
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);
|
||||
if (UNIV_UNLIKELY(!left_next_rec))
|
||||
{
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
ut_ad(!page_rec_is_metadata(left_next_rec));
|
||||
|
||||
/* This would likely be too large for a memory transaction. */
|
||||
LockMultiGuard g{lock_sys.rec_hash, l, r};
|
||||
const rec_t *left_next_rec= page_rec_get_next_const(orig_pred);
|
||||
ut_ad(!page_rec_is_metadata(left_next_rec));
|
||||
|
||||
/* Inherit the locks on the supremum of the left page to the
|
||||
first record which was moved from the right page */
|
||||
|
|
|
@ -88,7 +88,10 @@ page_cur_try_search_shortcut(
|
|||
goto exit_func;
|
||||
}
|
||||
|
||||
next_rec = page_rec_get_next_const(rec);
|
||||
if (!(next_rec = page_rec_get_next_const(rec))) {
|
||||
goto exit_func;
|
||||
}
|
||||
|
||||
if (!page_rec_is_supremum(next_rec)) {
|
||||
offsets = rec_get_offsets(next_rec, index, offsets,
|
||||
index->n_core_fields,
|
||||
|
@ -179,7 +182,10 @@ page_cur_try_search_shortcut_bytes(
|
|||
goto exit_func;
|
||||
}
|
||||
|
||||
next_rec = page_rec_get_next_const(rec);
|
||||
if (!(next_rec = page_rec_get_next_const(rec))) {
|
||||
goto exit_func;
|
||||
}
|
||||
|
||||
if (!page_rec_is_supremum(next_rec)) {
|
||||
offsets = rec_get_offsets(next_rec, index, offsets,
|
||||
index->n_core_fields,
|
||||
|
@ -267,7 +273,7 @@ page_cur_rec_field_extends(
|
|||
|
||||
/****************************************************************//**
|
||||
Searches the right position for a page cursor. */
|
||||
void
|
||||
bool
|
||||
page_cur_search_with_match(
|
||||
/*=======================*/
|
||||
const buf_block_t* block, /*!< in: buffer block */
|
||||
|
@ -289,7 +295,6 @@ page_cur_search_with_match(
|
|||
ulint low;
|
||||
ulint mid;
|
||||
const page_t* page;
|
||||
const page_dir_slot_t* slot;
|
||||
const rec_t* up_rec;
|
||||
const rec_t* low_rec;
|
||||
const rec_t* mid_rec;
|
||||
|
@ -335,7 +340,7 @@ page_cur_search_with_match(
|
|||
&& page_cur_try_search_shortcut(
|
||||
block, index, tuple,
|
||||
iup_matched_fields, ilow_matched_fields, cursor)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
# ifdef PAGE_CUR_DBG
|
||||
if (mode == PAGE_CUR_DBG) {
|
||||
|
@ -352,10 +357,9 @@ page_cur_search_with_match(
|
|||
if (mode == PAGE_CUR_RTREE_INSERT && n_core) {
|
||||
mode = PAGE_CUR_LE;
|
||||
} else {
|
||||
rtr_cur_search_with_match(
|
||||
return rtr_cur_search_with_match(
|
||||
block, (dict_index_t*)index, tuple, mode,
|
||||
cursor, rtr_info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,9 +390,11 @@ page_cur_search_with_match(
|
|||
|
||||
while (up - low > 1) {
|
||||
mid = (low + up) / 2;
|
||||
slot = page_dir_get_nth_slot(page, mid);
|
||||
mid_rec = page_dir_slot_get_rec(slot);
|
||||
|
||||
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)))) {
|
||||
goto corrupted;
|
||||
}
|
||||
cur_matched_fields = std::min(low_matched_fields,
|
||||
up_matched_fields);
|
||||
|
||||
|
@ -431,18 +437,30 @@ up_slot_match:
|
|||
}
|
||||
}
|
||||
|
||||
slot = page_dir_get_nth_slot(page, low);
|
||||
low_rec = page_dir_slot_get_rec(slot);
|
||||
slot = page_dir_get_nth_slot(page, up);
|
||||
up_rec = page_dir_slot_get_rec(slot);
|
||||
low_rec = page_dir_slot_get_rec_validate(
|
||||
page_dir_get_nth_slot(page, low));
|
||||
up_rec = page_dir_slot_get_rec_validate(
|
||||
page_dir_get_nth_slot(page, up));
|
||||
if (UNIV_UNLIKELY(!low_rec || !up_rec)) {
|
||||
corrupted:
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Perform linear search until the upper and lower records come to
|
||||
distance 1 of each other. */
|
||||
|
||||
while (page_rec_get_next_const(low_rec) != up_rec) {
|
||||
|
||||
mid_rec = page_rec_get_next_const(low_rec);
|
||||
|
||||
for (;;) {
|
||||
if (const rec_t* next = page_rec_get_next_const(low_rec)) {
|
||||
if (next == up_rec) {
|
||||
break;
|
||||
}
|
||||
mid_rec = next;
|
||||
} else {
|
||||
goto corrupted;
|
||||
}
|
||||
cur_matched_fields = std::min(low_matched_fields,
|
||||
up_matched_fields);
|
||||
|
||||
|
@ -512,6 +530,8 @@ up_rec_match:
|
|||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
|
@ -529,7 +549,7 @@ lower limit record
|
|||
@param[in,out] ilow_matched_bytes already matched bytes in the
|
||||
first partially matched field in the lower limit record
|
||||
@param[out] cursor page cursor */
|
||||
void
|
||||
bool
|
||||
page_cur_search_with_match_bytes(
|
||||
const buf_block_t* block,
|
||||
const dict_index_t* index,
|
||||
|
@ -543,9 +563,7 @@ page_cur_search_with_match_bytes(
|
|||
{
|
||||
ulint up;
|
||||
ulint low;
|
||||
ulint mid;
|
||||
const page_t* page;
|
||||
const page_dir_slot_t* slot;
|
||||
const rec_t* up_rec;
|
||||
const rec_t* low_rec;
|
||||
const rec_t* mid_rec;
|
||||
|
@ -594,7 +612,7 @@ page_cur_search_with_match_bytes(
|
|||
iup_matched_fields, iup_matched_bytes,
|
||||
ilow_matched_fields, ilow_matched_bytes,
|
||||
cursor)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
# ifdef PAGE_CUR_DBG
|
||||
if (mode == PAGE_CUR_DBG) {
|
||||
|
@ -632,9 +650,12 @@ page_cur_search_with_match_bytes(
|
|||
const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0;
|
||||
|
||||
while (up - low > 1) {
|
||||
mid = (low + up) / 2;
|
||||
slot = page_dir_get_nth_slot(page, mid);
|
||||
mid_rec = page_dir_slot_get_rec(slot);
|
||||
const ulint mid = (low + up) / 2;
|
||||
mid_rec = page_dir_slot_get_rec_validate(
|
||||
page_dir_get_nth_slot(page, mid));
|
||||
if (UNIV_UNLIKELY(!mid_rec)) {
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
|
||||
low_matched_fields, low_matched_bytes,
|
||||
|
@ -681,18 +702,30 @@ up_slot_match:
|
|||
}
|
||||
}
|
||||
|
||||
slot = page_dir_get_nth_slot(page, low);
|
||||
low_rec = page_dir_slot_get_rec(slot);
|
||||
slot = page_dir_get_nth_slot(page, up);
|
||||
up_rec = page_dir_slot_get_rec(slot);
|
||||
low_rec = page_dir_slot_get_rec_validate(
|
||||
page_dir_get_nth_slot(page, low));
|
||||
up_rec = page_dir_slot_get_rec_validate(
|
||||
page_dir_get_nth_slot(page, up));
|
||||
if (UNIV_UNLIKELY(!low_rec || !up_rec)) {
|
||||
corrupted:
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Perform linear search until the upper and lower records come to
|
||||
distance 1 of each other. */
|
||||
|
||||
while (page_rec_get_next_const(low_rec) != up_rec) {
|
||||
|
||||
mid_rec = page_rec_get_next_const(low_rec);
|
||||
|
||||
for (;;) {
|
||||
if (const rec_t* next = page_rec_get_next_const(low_rec)) {
|
||||
if (next == up_rec) {
|
||||
break;
|
||||
}
|
||||
mid_rec = next;
|
||||
} else {
|
||||
goto corrupted;
|
||||
}
|
||||
ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
|
||||
low_matched_fields, low_matched_bytes,
|
||||
up_matched_fields, up_matched_bytes);
|
||||
|
@ -761,6 +794,7 @@ up_rec_match:
|
|||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif /* BTR_CUR_HASH_ADAPT */
|
||||
|
||||
|
@ -773,17 +807,12 @@ page_cur_open_on_rnd_user_rec(
|
|||
buf_block_t* block, /*!< in: page */
|
||||
page_cur_t* cursor) /*!< out: page cursor */
|
||||
{
|
||||
const ulint n_recs = page_get_n_recs(block->page.frame);
|
||||
|
||||
page_cur_set_before_first(block, cursor);
|
||||
|
||||
if (UNIV_UNLIKELY(n_recs == 0)) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cursor->rec = page_rec_get_nth(block->page.frame,
|
||||
ut_rnd_interval(n_recs) + 1);
|
||||
cursor->block= block;
|
||||
if (const ulint n_recs= page_get_n_recs(block->page.frame))
|
||||
if ((cursor->rec= page_rec_get_nth(block->page.frame,
|
||||
ut_rnd_interval(n_recs) + 1)))
|
||||
return;
|
||||
cursor->rec= page_get_infimum_rec(block->page.frame);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -802,7 +831,7 @@ static void page_rec_set_n_owned(rec_t *rec, ulint n_owned, bool comp)
|
|||
Split a directory slot which owns too many records.
|
||||
@param[in,out] block index page
|
||||
@param[in,out] slot the slot that needs to be split */
|
||||
static void page_dir_split_slot(const buf_block_t &block,
|
||||
static bool page_dir_split_slot(const buf_block_t &block,
|
||||
page_dir_slot_t *slot)
|
||||
{
|
||||
ut_ad(slot <= &block.page.frame[srv_page_size - PAGE_EMPTY_DIR_START]);
|
||||
|
@ -815,10 +844,17 @@ static void page_dir_split_slot(const buf_block_t &block,
|
|||
PAGE_DIR_SLOT_MIN_N_OWNED, "compatibility");
|
||||
|
||||
/* Find a record approximately in the middle. */
|
||||
const rec_t *rec= page_dir_slot_get_rec(slot + PAGE_DIR_SLOT_SIZE);
|
||||
const rec_t *rec= page_dir_slot_get_rec_validate(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);
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(!rec))
|
||||
return true;
|
||||
|
||||
/* Add a directory slot immediately below this one. */
|
||||
constexpr uint16_t n_slots_f= PAGE_N_DIR_SLOTS + PAGE_HEADER;
|
||||
|
@ -828,7 +864,10 @@ static void page_dir_split_slot(const buf_block_t &block,
|
|||
page_dir_slot_t *last_slot= static_cast<page_dir_slot_t*>
|
||||
(block.page.frame + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) -
|
||||
n_slots * PAGE_DIR_SLOT_SIZE);
|
||||
ut_ad(slot >= last_slot);
|
||||
|
||||
if (UNIV_UNLIKELY(slot < last_slot))
|
||||
return true;
|
||||
|
||||
memmove_aligned<2>(last_slot, last_slot + PAGE_DIR_SLOT_SIZE,
|
||||
slot - last_slot);
|
||||
|
||||
|
@ -841,6 +880,7 @@ static void page_dir_split_slot(const buf_block_t &block,
|
|||
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),
|
||||
n_owned - half_owned, comp);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -866,6 +906,10 @@ static void page_zip_dir_split_slot(buf_block_t *block, ulint s, mtr_t* mtr)
|
|||
|
||||
const rec_t *rec= page_dir_slot_get_rec(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);
|
||||
|
||||
|
@ -951,8 +995,12 @@ 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<true>(block, slot_rec, 0, true, mtr);
|
||||
rec_t* new_rec = rec_get_next_ptr(slot_rec, TRUE);
|
||||
page_rec_set_n_owned<true>(block, new_rec,
|
||||
const rec_t* new_rec = page_rec_get_next_low(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
|
||||
be possible here if the buffer pool was corrupted later. */
|
||||
page_rec_set_n_owned<true>(block, const_cast<rec_t*>(new_rec),
|
||||
PAGE_DIR_SLOT_MIN_N_OWNED,
|
||||
true, mtr);
|
||||
mach_write_to_2(slot, page_offset(new_rec));
|
||||
|
@ -1013,18 +1061,27 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s)
|
|||
}
|
||||
|
||||
/* Transfer one record to the underfilled slot */
|
||||
rec_t* new_rec;
|
||||
const rec_t* new_rec;
|
||||
|
||||
if (comp) {
|
||||
if (UNIV_UNLIKELY(!(new_rec =
|
||||
page_rec_get_next_low(slot_rec, true)))) {
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
page_rec_set_n_owned(slot_rec, 0, true);
|
||||
new_rec = rec_get_next_ptr(slot_rec, TRUE);
|
||||
page_rec_set_n_owned(new_rec, PAGE_DIR_SLOT_MIN_N_OWNED, true);
|
||||
page_rec_set_n_owned(const_cast<rec_t*>(new_rec),
|
||||
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)))) {
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
page_rec_set_n_owned(slot_rec, 0, false);
|
||||
new_rec = rec_get_next_ptr(slot_rec, FALSE);
|
||||
page_rec_set_n_owned(new_rec, PAGE_DIR_SLOT_MIN_N_OWNED,
|
||||
false);
|
||||
page_rec_set_n_owned(const_cast<rec_t*>(new_rec),
|
||||
PAGE_DIR_SLOT_MIN_N_OWNED, false);
|
||||
page_rec_set_n_owned(up_rec, up_n_owned - 1, false);
|
||||
}
|
||||
|
||||
|
@ -1281,6 +1338,20 @@ inline void mtr_t::page_insert(const buf_block_t &block, bool reuse,
|
|||
m_last_offset= FIL_PAGE_TYPE;
|
||||
}
|
||||
|
||||
/** Report page directory corruption.
|
||||
@param block index page
|
||||
@param index index tree
|
||||
*/
|
||||
ATTRIBUTE_COLD
|
||||
static void page_cur_directory_corrupted(const buf_block_t &block,
|
||||
const dict_index_t &index)
|
||||
{
|
||||
ib::error() << "Directory of " << block.page.id()
|
||||
<< " of index " << index.name
|
||||
<< " in table " << index.table->name
|
||||
<< " is corrupted";
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor on an uncompressed page.
|
||||
@return pointer to record
|
||||
|
@ -1623,9 +1694,14 @@ copied:
|
|||
{
|
||||
const ulint owner= page_dir_find_owner_slot(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)))
|
||||
return nullptr;
|
||||
page_dir_split_slot(*block,
|
||||
page_dir_get_nth_slot(block->page.frame, owner));
|
||||
}
|
||||
|
||||
rec_offs_make_valid(insert_buf + extra_size, index,
|
||||
|
@ -1693,20 +1769,20 @@ static inline void page_zip_dir_add_slot(buf_block_t *block,
|
|||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor on a compressed and uncompressed
|
||||
page. Returns pointer to inserted record if succeed, i.e.,
|
||||
enough space available, NULL otherwise.
|
||||
The cursor stays at the same position.
|
||||
page.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
@return pointer to inserted record
|
||||
@return nullptr on failure */
|
||||
rec_t*
|
||||
page_cur_insert_rec_zip(
|
||||
/*====================*/
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor,
|
||||
logical position unchanged */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
const rec_t* rec, /*!< in: pointer to a physical record */
|
||||
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
|
||||
|
@ -1786,6 +1862,9 @@ page_cur_insert_rec_zip(
|
|||
{
|
||||
ulint pos= page_rec_get_n_recs_before(cursor->rec);
|
||||
|
||||
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
|
||||
return nullptr;
|
||||
|
||||
switch (page_zip_reorganize(cursor->block, index, level, mtr, true)) {
|
||||
case DB_FAIL:
|
||||
ut_ad(cursor->rec == cursor_rec);
|
||||
|
@ -1796,10 +1875,13 @@ page_cur_insert_rec_zip(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (pos)
|
||||
cursor->rec= page_rec_get_nth(page, pos);
|
||||
else
|
||||
ut_ad(cursor->rec == page_get_infimum_rec(page));
|
||||
if (!pos)
|
||||
ut_ad(cursor->rec == page + PAGE_NEW_INFIMUM);
|
||||
else if (!(cursor->rec= page_rec_get_nth(page, pos)))
|
||||
{
|
||||
cursor->rec= page + PAGE_NEW_SUPREMUM;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ut_ad(!page_header_get_ptr(page, PAGE_FREE));
|
||||
|
||||
|
@ -1816,16 +1898,21 @@ page_cur_insert_rec_zip(
|
|||
if (insert_rec)
|
||||
{
|
||||
ulint pos= page_rec_get_n_recs_before(insert_rec);
|
||||
ut_ad(pos > 0);
|
||||
if (UNIV_UNLIKELY(!pos || pos == ULINT_UNDEFINED))
|
||||
return nullptr;
|
||||
|
||||
/* We are writing entire page images to the log. Reduce the redo
|
||||
log volume by reorganizing the page at the same time. */
|
||||
switch (page_zip_reorganize(cursor->block, index, level, mtr)) {
|
||||
case DB_SUCCESS:
|
||||
/* The page was reorganized: Seek to pos. */
|
||||
cursor->rec= pos > 1
|
||||
? page_rec_get_nth(page, pos - 1)
|
||||
: page + PAGE_NEW_INFIMUM;
|
||||
if (pos <= 1)
|
||||
cursor->rec= page + PAGE_NEW_INFIMUM;
|
||||
else if (!(cursor->rec= page_rec_get_nth(page, pos - 1)))
|
||||
{
|
||||
cursor->rec= page + PAGE_NEW_INFIMUM;
|
||||
return nullptr;
|
||||
}
|
||||
insert_rec= page + rec_get_next_offs(cursor->rec, 1);
|
||||
rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets);
|
||||
break;
|
||||
|
@ -1891,19 +1978,25 @@ too_small:
|
|||
|
||||
byte *const free_rec_ptr= page + free_rec;
|
||||
heap_no= rec_get_heap_no_new(free_rec_ptr);
|
||||
int16_t next_rec= mach_read_from_2(free_rec_ptr - REC_NEXT);
|
||||
int16_t next_free= mach_read_from_2(free_rec_ptr - REC_NEXT);
|
||||
/* With innodb_page_size=64k, int16_t would be unsafe to use here,
|
||||
but that cannot be used with ROW_FORMAT=COMPRESSED. */
|
||||
static_assert(UNIV_ZIP_SIZE_SHIFT_MAX == 14, "compatibility");
|
||||
if (next_rec)
|
||||
if (next_free)
|
||||
{
|
||||
next_rec= static_cast<int16_t>(next_rec + free_rec);
|
||||
ut_ad(int{PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES} <= next_rec);
|
||||
ut_ad(static_cast<uint16_t>(next_rec) < srv_page_size);
|
||||
next_free= static_cast<int16_t>(next_free + free_rec);
|
||||
if (UNIV_UNLIKELY(int{PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES} >
|
||||
next_free ||
|
||||
uint16_t(next_free) >= srv_page_size))
|
||||
{
|
||||
if (UNIV_LIKELY_NULL(heap))
|
||||
mem_heap_free(heap);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
byte *hdr= my_assume_aligned<4>(&page_zip->data[page_free_f]);
|
||||
mach_write_to_2(hdr, static_cast<uint16_t>(next_rec));
|
||||
mach_write_to_2(hdr, static_cast<uint16_t>(next_free));
|
||||
const byte *const garbage= my_assume_aligned<2>(page_free + 2);
|
||||
ut_ad(mach_read_from_2(garbage) >= rec_size);
|
||||
mach_write_to_2(my_assume_aligned<2>(hdr + 2),
|
||||
|
@ -1959,18 +2052,20 @@ use_heap:
|
|||
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);
|
||||
if (UNIV_UNLIKELY(!next_rec ||
|
||||
rec_get_status(next_rec) == REC_STATUS_INFIMUM ||
|
||||
rec_get_status(cursor->rec) > REC_STATUS_INFIMUM))
|
||||
return nullptr;
|
||||
|
||||
/* 3. Create the record */
|
||||
byte *insert_rec= rec_copy(insert_buf, rec, offsets);
|
||||
rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets);
|
||||
|
||||
/* 4. Insert the record in the linked list of records */
|
||||
ut_ad(cursor->rec != insert_rec);
|
||||
|
||||
/* next record after current before the insertion */
|
||||
const rec_t* next_rec = page_rec_get_next_low(cursor->rec, TRUE);
|
||||
ut_ad(rec_get_status(cursor->rec) <= REC_STATUS_INFIMUM);
|
||||
ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
|
||||
ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
|
||||
|
||||
mach_write_to_2(insert_rec - REC_NEXT, static_cast<uint16_t>
|
||||
(next_rec - insert_rec));
|
||||
|
@ -2037,8 +2132,9 @@ inc_dir:
|
|||
/* 7. It remains to update the owner record. */
|
||||
ulint n_owned;
|
||||
|
||||
while (!(n_owned = rec_get_n_owned_new(next_rec)))
|
||||
next_rec= page_rec_get_next_low(next_rec, true);
|
||||
while (!(n_owned= rec_get_n_owned_new(next_rec)))
|
||||
if (!(next_rec= page_rec_get_next_low(next_rec, true)))
|
||||
return nullptr;
|
||||
|
||||
rec_set_bit_field_1(const_cast<rec_t*>(next_rec), n_owned + 1,
|
||||
REC_NEW_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
|
||||
|
@ -2052,7 +2148,10 @@ inc_dir:
|
|||
{
|
||||
const ulint owner= page_dir_find_owner_slot(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);
|
||||
}
|
||||
|
||||
|
@ -2185,8 +2284,8 @@ page_cur_delete_rec(
|
|||
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. */
|
||||
page_cur_move_to_next(cursor);
|
||||
ut_ad(page_cur_is_after_last(cursor));
|
||||
ut_ad(page_rec_is_supremum(page_rec_get_next(cursor->rec)));
|
||||
page_cur_set_after_last(block, cursor);
|
||||
page_create_empty(page_cur_get_block(cursor),
|
||||
const_cast<dict_index_t*>(index), mtr);
|
||||
return;
|
||||
|
@ -2197,6 +2296,7 @@ page_cur_delete_rec(
|
|||
|
||||
if (UNIV_UNLIKELY(!cur_slot_no || cur_slot_no == ULINT_UNDEFINED)) {
|
||||
/* Avoid crashing due to a corrupted page. */
|
||||
page_cur_directory_corrupted(*block, *index);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2220,11 +2320,16 @@ page_cur_delete_rec(
|
|||
|
||||
while (current_rec != rec) {
|
||||
prev_rec = rec;
|
||||
rec = page_rec_get_next(rec);
|
||||
if (!(rec = page_rec_get_next(rec))) {
|
||||
/* Avoid crashing due to a corrupted page. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
page_cur_move_to_next(cursor);
|
||||
next_rec = cursor->rec;
|
||||
if (!(next_rec = page_cur_move_to_next(cursor))) {
|
||||
/* Avoid crashing due to a corrupted page. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remove the record from the linked list of records */
|
||||
/* If the deleted record is pointed to by a dir slot, update the
|
||||
|
@ -2546,7 +2651,7 @@ inc_dir:
|
|||
mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1);
|
||||
|
||||
if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED))
|
||||
page_dir_split_slot(block, owner_slot);
|
||||
return page_dir_split_slot(block, owner_slot);
|
||||
ut_ad(page_simple_validate_old(page));
|
||||
return false;
|
||||
}
|
||||
|
@ -2771,7 +2876,7 @@ inc_dir:
|
|||
mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1);
|
||||
|
||||
if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED))
|
||||
page_dir_split_slot(block, owner_slot);
|
||||
return page_dir_split_slot(block, owner_slot);
|
||||
ut_ad(page_simple_validate_new(page));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -99,43 +99,25 @@ page_dir_find_owner_slot(
|
|||
|
||||
if (page_is_comp(page)) {
|
||||
while (rec_get_n_owned_new(r) == 0) {
|
||||
r = rec_get_next_ptr_const(r, TRUE);
|
||||
ut_ad(r >= page + PAGE_NEW_SUPREMUM);
|
||||
ut_ad(r < page + (srv_page_size - PAGE_DIR));
|
||||
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 = rec_get_next_ptr_const(r, FALSE);
|
||||
ut_ad(r >= page + PAGE_OLD_SUPREMUM);
|
||||
ut_ad(r < page + (srv_page_size - PAGE_DIR));
|
||||
r = page_rec_get_next_low(r, false);
|
||||
if (UNIV_UNLIKELY(r < page + PAGE_OLD_SUPREMUM
|
||||
|| r >= slot)) {
|
||||
return ULINT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16 rec_offs_bytes = mach_encode_2(ulint(r - page));
|
||||
|
||||
while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
|
||||
|
||||
while (UNIV_LIKELY(*(uint16*) slot
|
||||
!= mach_encode_2(ulint(r - page)))) {
|
||||
if (UNIV_UNLIKELY(slot == first_slot)) {
|
||||
ib::error() << "Probable data corruption on page "
|
||||
<< page_get_page_no(page)
|
||||
<< ". Original record on that page;";
|
||||
|
||||
if (page_is_comp(page)) {
|
||||
fputs("(compact record)", stderr);
|
||||
} else {
|
||||
rec_print_old(stderr, rec);
|
||||
}
|
||||
|
||||
ib::error() << "Cannot find the dir slot for this"
|
||||
" record on that page;";
|
||||
|
||||
if (page_is_comp(page)) {
|
||||
fputs("(compact record)", stderr);
|
||||
} else {
|
||||
rec_print_old(stderr, page
|
||||
+ mach_decode_2(rec_offs_bytes));
|
||||
}
|
||||
|
||||
return ULINT_UNDEFINED;
|
||||
}
|
||||
|
||||
|
@ -478,9 +460,8 @@ page_copy_rec_list_end_no_locks(
|
|||
|
||||
page_cur_position(rec, block, &cur1);
|
||||
|
||||
if (page_cur_is_before_first(&cur1)) {
|
||||
|
||||
page_cur_move_to_next(&cur1);
|
||||
if (page_cur_is_before_first(&cur1) && !page_cur_move_to_next(&cur1)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(page_is_comp(new_page) != page_rec_is_comp(rec)
|
||||
|
@ -504,12 +485,10 @@ page_copy_rec_list_end_no_locks(
|
|||
ULINT_UNDEFINED, &heap);
|
||||
ins_rec = page_cur_insert_rec_low(&cur2, index,
|
||||
cur1.rec, offsets, mtr);
|
||||
if (UNIV_UNLIKELY(!ins_rec)) {
|
||||
if (UNIV_UNLIKELY(!ins_rec || !page_cur_move_to_next(&cur1))) {
|
||||
err = DB_CORRUPTION;
|
||||
break;
|
||||
}
|
||||
|
||||
page_cur_move_to_next(&cur1);
|
||||
ut_ad(!(rec_get_info_bits(cur1.rec, page_is_comp(new_page))
|
||||
& REC_INFO_MIN_REC_FLAG));
|
||||
cur2.rec = ins_rec;
|
||||
|
@ -550,10 +529,13 @@ page_copy_rec_list_end(
|
|||
rec_t* ret = page_rec_get_next(
|
||||
page_get_infimum_rec(new_page));
|
||||
ulint num_moved = 0;
|
||||
rtr_rec_move_t* rec_move = NULL;
|
||||
mem_heap_t* heap = NULL;
|
||||
ut_ad(page_align(rec) == page);
|
||||
|
||||
if (UNIV_UNLIKELY(!ret)) {
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
if (new_page_zip) {
|
||||
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
|
||||
|
@ -579,15 +561,15 @@ page_copy_rec_list_end(
|
|||
alignas(2) byte h[PAGE_N_DIRECTION + 2 - PAGE_LAST_INSERT];
|
||||
memcpy_aligned<2>(h, PAGE_HEADER + PAGE_LAST_INSERT + new_page,
|
||||
sizeof h);
|
||||
mem_heap_t* heap = nullptr;
|
||||
rtr_rec_move_t* rec_move = nullptr;
|
||||
|
||||
if (index->is_spatial()) {
|
||||
ulint max_to_move = page_get_n_recs(
|
||||
buf_block_get_frame(block));
|
||||
heap = mem_heap_create(256);
|
||||
|
||||
rec_move = static_cast<rtr_rec_move_t*>(
|
||||
rec_move= static_cast<rtr_rec_move_t*>(
|
||||
mem_heap_alloc(heap, max_to_move * sizeof *rec_move));
|
||||
|
||||
/* For spatial index, we need to insert recs one by one
|
||||
to keep recs ordered. */
|
||||
*err = rtr_page_copy_rec_list_end_no_locks(new_block,
|
||||
|
@ -600,6 +582,10 @@ page_copy_rec_list_end(
|
|||
*err = page_copy_rec_list_end_no_locks(new_block, block, rec,
|
||||
index, mtr);
|
||||
if (UNIV_UNLIKELY(*err != DB_SUCCESS)) {
|
||||
err_exit:
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (was_empty) {
|
||||
|
@ -640,7 +626,11 @@ page_copy_rec_list_end(
|
|||
have at least one predecessor (the predefined
|
||||
infimum record, or a freshly copied record
|
||||
that is smaller than "ret"). */
|
||||
ut_a(ret_pos > 0);
|
||||
if (UNIV_UNLIKELY(!ret_pos
|
||||
|| ret_pos == ULINT_UNDEFINED)) {
|
||||
*err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
*err = page_zip_reorganize(new_block, index,
|
||||
page_zip_level, mtr);
|
||||
|
@ -653,14 +643,12 @@ page_copy_rec_list_end(
|
|||
ut_ad(page_validate(new_page, index));
|
||||
/* fall through */
|
||||
default:
|
||||
if (heap) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
return nullptr;
|
||||
goto err_exit;
|
||||
case DB_SUCCESS:
|
||||
/* The page was reorganized:
|
||||
Seek to ret_pos. */
|
||||
ret = page_rec_get_nth(new_page, ret_pos);
|
||||
ut_ad(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -668,13 +656,13 @@ page_copy_rec_list_end(
|
|||
/* Update the lock table and possible hash index */
|
||||
|
||||
if (!index->has_locking()) {
|
||||
} else if (rec_move && dict_index_is_spatial(index)) {
|
||||
} else if (UNIV_LIKELY_NULL(rec_move)) {
|
||||
lock_rtr_move_rec_list(new_block, block, rec_move, num_moved);
|
||||
} else {
|
||||
lock_move_rec_list_end(new_block, block, rec);
|
||||
}
|
||||
|
||||
if (heap) {
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
|
@ -721,8 +709,9 @@ page_copy_rec_list_start(
|
|||
rec_offs_init(offsets_);
|
||||
|
||||
if (UNIV_UNLIKELY(!ret)) {
|
||||
corrupted:
|
||||
*err = DB_CORRUPTION;
|
||||
return ret;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Here, "ret" may be pointing to a user record or the
|
||||
|
@ -733,15 +722,17 @@ page_copy_rec_list_start(
|
|||
return(ret);
|
||||
}
|
||||
|
||||
page_cur_set_before_first(block, &cur1);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
mtr_log_t log_mode = MTR_LOG_NONE;
|
||||
|
||||
if (new_page_zip) {
|
||||
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
|
||||
}
|
||||
|
||||
page_cur_set_before_first(block, &cur1);
|
||||
page_cur_move_to_next(&cur1);
|
||||
|
||||
page_cur_position(ret, new_block, &cur2);
|
||||
|
||||
const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0;
|
||||
|
@ -775,12 +766,12 @@ page_copy_rec_list_start(
|
|||
cur2.rec = page_cur_insert_rec_low(&cur2, index,
|
||||
cur1.rec, offsets,
|
||||
mtr);
|
||||
if (UNIV_UNLIKELY(!cur2.rec)) {
|
||||
if (UNIV_UNLIKELY(!cur2.rec
|
||||
|| !page_cur_move_to_next(&cur1))) {
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
page_cur_move_to_next(&cur1);
|
||||
ut_ad(!(rec_get_info_bits(cur1.rec,
|
||||
page_is_comp(new_page))
|
||||
& REC_INFO_MIN_REC_FLAG));
|
||||
|
@ -821,11 +812,17 @@ zip_reorganize:
|
|||
the predefined infimum record, then it would
|
||||
still be the infimum, and we would have
|
||||
ret_pos == 0. */
|
||||
if (UNIV_UNLIKELY(!ret_pos
|
||||
|| ret_pos == ULINT_UNDEFINED)) {
|
||||
*err = DB_CORRUPTION;
|
||||
return nullptr;
|
||||
}
|
||||
*err = page_zip_reorganize(new_block, index,
|
||||
page_zip_level, mtr);
|
||||
switch (*err) {
|
||||
case DB_SUCCESS:
|
||||
ret = page_rec_get_nth(new_page, ret_pos);
|
||||
ut_ad(ret);
|
||||
break;
|
||||
case DB_FAIL:
|
||||
if (UNIV_UNLIKELY
|
||||
|
@ -936,7 +933,7 @@ page_delete_rec_list_end(
|
|||
page_cur_position(rec, block, &cur);
|
||||
offsets= rec_get_offsets(rec, index, offsets, n_core,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
rec= rec_get_next_ptr(rec, TRUE);
|
||||
rec= const_cast<rec_t*>(page_rec_get_next_low(rec, true));
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
ut_a(page_zip_validate(&block->page.zip, page, index));
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
|
@ -981,12 +978,15 @@ page_delete_rec_list_end(
|
|||
if (scrub)
|
||||
mtr->memset(block, page_offset(rec2), rec_offs_data_size(offsets), 0);
|
||||
|
||||
rec2 = page_rec_get_next(rec2);
|
||||
rec2= page_rec_get_next(rec2);
|
||||
}
|
||||
while (!page_rec_is_supremum(rec2));
|
||||
while (rec2 && !page_rec_is_supremum(rec2));
|
||||
|
||||
if (UNIV_LIKELY_NULL(heap))
|
||||
mem_heap_free(heap);
|
||||
|
||||
if (UNIV_UNLIKELY(!rec))
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
ut_ad(size < srv_page_size);
|
||||
|
@ -1000,13 +1000,15 @@ page_delete_rec_list_end(
|
|||
while (!(n_owned= rec_get_n_owned_new(owner_rec)))
|
||||
{
|
||||
count++;
|
||||
owner_rec= rec_get_next_ptr_const(owner_rec, TRUE);
|
||||
if (!(owner_rec= page_rec_get_next_low(owner_rec, true)))
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
else
|
||||
while (!(n_owned= rec_get_n_owned_old(owner_rec)))
|
||||
{
|
||||
count++;
|
||||
owner_rec= rec_get_next_ptr_const(owner_rec, FALSE);
|
||||
if (!(owner_rec= page_rec_get_next_low(owner_rec, false)))
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
ut_ad(n_owned > count);
|
||||
|
@ -1133,7 +1135,10 @@ page_delete_rec_list_start(
|
|||
}
|
||||
|
||||
page_cur_set_before_first(block, &cur1);
|
||||
page_cur_move_to_next(&cur1);
|
||||
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
|
||||
ut_ad("corrupted page" == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const ulint n_core = page_rec_is_leaf(rec)
|
||||
? index->n_core_fields : 0;
|
||||
|
@ -1153,7 +1158,8 @@ page_delete_rec_list_start(
|
|||
/************************************************************//**
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
@return nth record
|
||||
@retval nullptr on corrupted page */
|
||||
const rec_t*
|
||||
page_rec_get_nth_const(
|
||||
/*===================*/
|
||||
|
@ -1172,7 +1178,6 @@ page_rec_get_nth_const(
|
|||
ut_ad(nth < srv_page_size / (REC_N_NEW_EXTRA_BYTES + 1));
|
||||
|
||||
for (i = 0;; i++) {
|
||||
|
||||
slot = page_dir_get_nth_slot(page, i);
|
||||
n_owned = page_dir_slot_get_n_owned(slot);
|
||||
|
||||
|
@ -1183,87 +1188,154 @@ page_rec_get_nth_const(
|
|||
}
|
||||
}
|
||||
|
||||
ut_ad(i > 0);
|
||||
slot = page_dir_get_nth_slot(page, i - 1);
|
||||
rec = page_dir_slot_get_rec(slot);
|
||||
if (UNIV_UNLIKELY(!i)) {
|
||||
return nullptr;
|
||||
}
|
||||
rec = page_dir_slot_get_rec(slot + 2);
|
||||
|
||||
if (page_is_comp(page)) {
|
||||
do {
|
||||
rec = page_rec_get_next_low(rec, TRUE);
|
||||
ut_ad(rec);
|
||||
} while (nth--);
|
||||
} while (rec && nth--);
|
||||
} else {
|
||||
do {
|
||||
rec = page_rec_get_next_low(rec, FALSE);
|
||||
ut_ad(rec);
|
||||
} while (nth--);
|
||||
} while (rec && nth--);
|
||||
}
|
||||
|
||||
return(rec);
|
||||
}
|
||||
|
||||
/***************************************************************//**
|
||||
Returns the number of records before the given record in chain.
|
||||
The number includes infimum and supremum records.
|
||||
@return number of records */
|
||||
ulint
|
||||
page_rec_get_n_recs_before(
|
||||
/*=======================*/
|
||||
const rec_t* rec) /*!< in: the physical 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 */
|
||||
{
|
||||
const page_dir_slot_t* slot;
|
||||
const rec_t* slot_rec;
|
||||
const page_t* page;
|
||||
ulint i;
|
||||
lint n = 0;
|
||||
const rec_t* rec2;
|
||||
const rec_t* prev_rec = NULL;
|
||||
|
||||
ut_ad(page_rec_check(rec));
|
||||
|
||||
page = page_align(rec);
|
||||
const page_t* const page = page_align(rec);
|
||||
|
||||
ut_ad(!page_rec_is_infimum(rec));
|
||||
|
||||
ulint slot_no = page_dir_find_owner_slot(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);
|
||||
|
||||
if (UNIV_UNLIKELY(!(rec2 = page_dir_slot_get_rec_validate(slot)))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (page_is_comp(page)) {
|
||||
while (rec_get_n_owned_new(rec) == 0) {
|
||||
|
||||
rec = rec_get_next_ptr_const(rec, TRUE);
|
||||
n--;
|
||||
while (rec2 && rec != rec2) {
|
||||
prev_rec = rec2;
|
||||
ulint offs = rec_get_next_offs(rec2, TRUE);
|
||||
if (offs < PAGE_NEW_INFIMUM
|
||||
|| offs > page_header_get_field(page,
|
||||
PAGE_HEAP_TOP)) {
|
||||
return nullptr;
|
||||
}
|
||||
rec2 = page + offs;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
slot = page_dir_get_nth_slot(page, i);
|
||||
slot_rec = page_dir_slot_get_rec(slot);
|
||||
|
||||
n += lint(rec_get_n_owned_new(slot_rec));
|
||||
|
||||
if (rec == slot_rec) {
|
||||
|
||||
switch (rec_get_status(prev_rec)) {
|
||||
case REC_STATUS_INSTANT:
|
||||
case REC_STATUS_ORDINARY:
|
||||
if (!page_is_leaf(page)) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case REC_STATUS_INFIMUM:
|
||||
break;
|
||||
case REC_STATUS_NODE_PTR:
|
||||
if (!page_is_leaf(page)) {
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
while (rec_get_n_owned_old(rec) == 0) {
|
||||
|
||||
rec = rec_get_next_ptr_const(rec, FALSE);
|
||||
n--;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
slot = page_dir_get_nth_slot(page, i);
|
||||
slot_rec = page_dir_slot_get_rec(slot);
|
||||
|
||||
n += lint(rec_get_n_owned_old(slot_rec));
|
||||
|
||||
if (rec == slot_rec) {
|
||||
|
||||
break;
|
||||
while (rec2 && rec != rec2) {
|
||||
prev_rec = rec2;
|
||||
ulint offs = rec_get_next_offs(rec2, FALSE);
|
||||
if (offs < PAGE_OLD_INFIMUM
|
||||
|| offs > page_header_get_field(page,
|
||||
PAGE_HEAP_TOP)) {
|
||||
return nullptr;
|
||||
}
|
||||
rec2 = page + offs;
|
||||
}
|
||||
}
|
||||
|
||||
n--;
|
||||
return(prev_rec);
|
||||
}
|
||||
|
||||
ut_ad(n >= 0);
|
||||
ut_ad((ulong) n < srv_page_size / (REC_N_NEW_EXTRA_BYTES + 1));
|
||||
/** Return the number of preceding records in an 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)
|
||||
{
|
||||
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);
|
||||
|
||||
return((ulint) n);
|
||||
lint n= 0;
|
||||
|
||||
ut_ad(page_rec_check(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))))
|
||||
return ULINT_UNDEFINED;
|
||||
|
||||
do
|
||||
{
|
||||
const rec_t *slot_rec= page_dir_slot_get_rec_validate(slot);
|
||||
if (UNIV_UNLIKELY(!slot_rec))
|
||||
break;
|
||||
n+= lint(rec_get_n_owned_new(slot_rec));
|
||||
|
||||
if (rec == slot_rec)
|
||||
goto found;
|
||||
}
|
||||
while ((slot-= 2) > end_slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; rec_get_n_owned_old(rec) == 0; n--)
|
||||
if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(rec, false))))
|
||||
return ULINT_UNDEFINED;
|
||||
|
||||
do
|
||||
{
|
||||
const rec_t *slot_rec= page_dir_slot_get_rec_validate(slot);
|
||||
if (UNIV_UNLIKELY(!slot_rec))
|
||||
break;
|
||||
n+= lint(rec_get_n_owned_old(slot_rec));
|
||||
|
||||
if (rec == slot_rec)
|
||||
goto found;
|
||||
}
|
||||
while ((slot-= 2) > end_slot);
|
||||
}
|
||||
|
||||
return ULINT_UNDEFINED;
|
||||
found:
|
||||
return --n < 0 ? ULINT_UNDEFINED : ulint(n);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
@ -1783,15 +1855,14 @@ page_simple_validate_new(
|
|||
slot_no = 0;
|
||||
slot = page_dir_get_nth_slot(page, slot_no);
|
||||
|
||||
rec = page_get_infimum_rec(page);
|
||||
rec = page + PAGE_NEW_INFIMUM;
|
||||
|
||||
for (;;) {
|
||||
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
|
||||
|
||||
if (UNIV_UNLIKELY(rec < page + PAGE_NEW_INFIMUM
|
||||
|| rec > rec_heap_top)) {
|
||||
ib::error() << "Record " << page_offset(rec)
|
||||
<< " is above rec heap top "
|
||||
<< " is out of bounds: "
|
||||
<< page_offset(rec_heap_top);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
|
@ -2247,14 +2318,21 @@ wrong_page_type:
|
|||
}
|
||||
|
||||
next_rec:
|
||||
if (page_rec_is_supremum(rec)) {
|
||||
old_rec = rec;
|
||||
rec = page_rec_get_next_const(rec);
|
||||
|
||||
if (UNIV_UNLIKELY(!rec != page_rec_is_supremum(old_rec))) {
|
||||
ib::error() << "supremum is not last record: " << offs;
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
if (!rec) {
|
||||
rec = old_rec; /* supremum */
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
own_count++;
|
||||
old_rec = rec;
|
||||
rec = page_rec_get_next_const(rec);
|
||||
|
||||
if (page_rec_is_infimum(old_rec)
|
||||
&& page_rec_is_user_rec(rec)) {
|
||||
|
@ -2409,37 +2487,36 @@ page_find_rec_with_heap_no(
|
|||
@param[in] page index tree leaf page
|
||||
@return the last record, not delete-marked
|
||||
@retval infimum record if all records are delete-marked */
|
||||
const rec_t*
|
||||
page_find_rec_max_not_deleted(
|
||||
const page_t* page)
|
||||
const rec_t *page_find_rec_max_not_deleted(const page_t *page)
|
||||
{
|
||||
const rec_t* rec = page_get_infimum_rec(page);
|
||||
const rec_t* prev_rec = NULL; // remove warning
|
||||
ut_ad(page_is_leaf(page));
|
||||
|
||||
/* Because the page infimum is never delete-marked
|
||||
and never the metadata pseudo-record (MIN_REC_FLAG)),
|
||||
prev_rec will always be assigned to it first. */
|
||||
ut_ad(!rec_get_info_bits(rec, page_rec_is_comp(rec)));
|
||||
ut_ad(page_is_leaf(page));
|
||||
|
||||
if (page_is_comp(page)) {
|
||||
do {
|
||||
if (!(rec[-REC_NEW_INFO_BITS]
|
||||
& (REC_INFO_DELETED_FLAG
|
||||
| REC_INFO_MIN_REC_FLAG))) {
|
||||
prev_rec = rec;
|
||||
}
|
||||
rec = page_rec_get_next_low(rec, true);
|
||||
} while (rec != page + PAGE_NEW_SUPREMUM);
|
||||
} else {
|
||||
do {
|
||||
if (!(rec[-REC_OLD_INFO_BITS]
|
||||
& (REC_INFO_DELETED_FLAG
|
||||
| REC_INFO_MIN_REC_FLAG))) {
|
||||
prev_rec = rec;
|
||||
}
|
||||
rec = page_rec_get_next_low(rec, false);
|
||||
} while (rec != page + PAGE_OLD_SUPREMUM);
|
||||
}
|
||||
return(prev_rec);
|
||||
if (page_is_comp(page))
|
||||
{
|
||||
const rec_t *rec= page + PAGE_NEW_INFIMUM;
|
||||
const rec_t *prev_rec= rec;
|
||||
do
|
||||
{
|
||||
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)))
|
||||
return page + PAGE_NEW_INFIMUM;
|
||||
} while (rec != page + PAGE_NEW_SUPREMUM);
|
||||
return prev_rec;
|
||||
}
|
||||
else
|
||||
{
|
||||
const rec_t *rec= page + PAGE_OLD_INFIMUM;
|
||||
const rec_t *prev_rec= rec;
|
||||
do
|
||||
{
|
||||
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)))
|
||||
return page + PAGE_OLD_INFIMUM;
|
||||
} while (rec != page + PAGE_OLD_SUPREMUM);
|
||||
return prev_rec;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -864,19 +864,19 @@ rec_get_offsets_func(
|
|||
ut_ad(!n_core);
|
||||
n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1;
|
||||
break;
|
||||
default:
|
||||
ut_ad("corrupted record header" == 0);
|
||||
/* fall through */
|
||||
case REC_STATUS_INFIMUM:
|
||||
case REC_STATUS_SUPREMUM:
|
||||
/* infimum or supremum record */
|
||||
ut_ad(rec_get_heap_no_new(rec)
|
||||
== ulint(rec_get_status(rec)
|
||||
== REC_STATUS_INFIMUM
|
||||
? PAGE_HEAP_NO_INFIMUM
|
||||
: PAGE_HEAP_NO_SUPREMUM));
|
||||
== REC_STATUS_INFIMUM
|
||||
? PAGE_HEAP_NO_INFIMUM
|
||||
: PAGE_HEAP_NO_SUPREMUM));
|
||||
n = 1;
|
||||
break;
|
||||
default:
|
||||
ut_error;
|
||||
return(NULL);
|
||||
}
|
||||
} else {
|
||||
n = rec_get_n_fields_old(rec);
|
||||
|
|
|
@ -257,19 +257,17 @@ public:
|
|||
}
|
||||
|
||||
/** Position the cursor on the first user record. */
|
||||
void open(buf_block_t* block) UNIV_NOTHROW
|
||||
rec_t* open(buf_block_t* block) noexcept
|
||||
MY_ATTRIBUTE((warn_unused_result))
|
||||
{
|
||||
page_cur_set_before_first(block, &m_cur);
|
||||
|
||||
if (!end()) {
|
||||
next();
|
||||
}
|
||||
return next();
|
||||
}
|
||||
|
||||
/** Move to the next record. */
|
||||
void next() UNIV_NOTHROW
|
||||
rec_t* next() noexcept MY_ATTRIBUTE((warn_unused_result))
|
||||
{
|
||||
page_cur_move_to_next(&m_cur);
|
||||
return page_cur_move_to_next(&m_cur);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1532,6 +1530,8 @@ inline bool IndexPurge::open() noexcept
|
|||
return false;
|
||||
|
||||
rec_t *rec= page_rec_get_next(btr_pcur_get_rec(&m_pcur));
|
||||
if (!rec)
|
||||
return false;
|
||||
if (rec_is_metadata(rec, *m_index))
|
||||
/* Skip the metadata pseudo-record. */
|
||||
btr_pcur_get_page_cur(&m_pcur)->rec= rec;
|
||||
|
@ -1543,7 +1543,9 @@ Position the cursor on the next record.
|
|||
@return DB_SUCCESS or error code */
|
||||
dberr_t IndexPurge::next() noexcept
|
||||
{
|
||||
btr_pcur_move_to_next_on_page(&m_pcur);
|
||||
if (UNIV_UNLIKELY(!btr_pcur_move_to_next_on_page(&m_pcur))) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
/* When switching pages, commit the mini-transaction
|
||||
in order to release the latch on the old page. */
|
||||
|
@ -1581,8 +1583,8 @@ dberr_t IndexPurge::next() noexcept
|
|||
&m_mtr)) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
btr_pcur_move_to_next_on_page(&m_pcur);
|
||||
} else if (!btr_pcur_move_to_next_on_page(&m_pcur)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
} while (!btr_pcur_is_on_user_rec(&m_pcur));
|
||||
|
||||
|
@ -1799,7 +1801,9 @@ PageConverter::update_records(
|
|||
|
||||
/* This will also position the cursor on the first user record. */
|
||||
|
||||
m_rec_iter.open(block);
|
||||
if (!m_rec_iter.open(block)) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
while (!m_rec_iter.end()) {
|
||||
rec_t* rec = m_rec_iter.current();
|
||||
|
@ -1830,17 +1834,19 @@ PageConverter::update_records(
|
|||
optimistic delete. */
|
||||
|
||||
if (deleted) {
|
||||
++m_index->m_stats.m_n_deleted;
|
||||
/* A successful purge will move the cursor to the
|
||||
next record. */
|
||||
|
||||
if (!purge()) {
|
||||
m_rec_iter.next();
|
||||
if (purge()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++m_index->m_stats.m_n_deleted;
|
||||
} else {
|
||||
++m_index->m_stats.m_n_rows;
|
||||
m_rec_iter.next();
|
||||
}
|
||||
|
||||
if (!m_rec_iter.next()) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3181,6 +3187,8 @@ 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()));
|
||||
if (!rec)
|
||||
return DB_CORRUPTION;
|
||||
|
||||
/* Relax the assertion in rec_init_offsets(). */
|
||||
ut_ad(!index->in_instant_init);
|
||||
|
@ -3205,18 +3213,22 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
|
|||
return err;
|
||||
}
|
||||
|
||||
const auto *rec= page_rec_get_next(page_get_infimum_rec(page.get()));
|
||||
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 info_bits= rec_get_info_bits(rec, comp);
|
||||
|
||||
if (page_rec_is_supremum(rec) || !(info_bits & REC_INFO_MIN_REC_FLAG))
|
||||
if (!rec || page_rec_is_supremum(rec))
|
||||
{
|
||||
corrupted_metadata:
|
||||
ib::error() << "Table " << index->table->name
|
||||
<< " is missing instant ALTER metadata";
|
||||
index->table->corrupted= true;
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
const auto info_bits= rec_get_info_bits(rec, comp);
|
||||
if (!(info_bits & REC_INFO_MIN_REC_FLAG))
|
||||
goto corrupted_metadata;
|
||||
|
||||
if ((info_bits & ~REC_INFO_DELETED_FLAG) != REC_INFO_MIN_REC_FLAG ||
|
||||
(comp && rec_get_status(rec) != REC_STATUS_INSTANT))
|
||||
{
|
||||
|
|
|
@ -2229,7 +2229,9 @@ row_ins_duplicate_error_in_clust_online(
|
|||
}
|
||||
}
|
||||
|
||||
rec = page_rec_get_next_const(btr_cur_get_rec(cursor));
|
||||
if (!(rec = page_rec_get_next_const(btr_cur_get_rec(cursor)))) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
if (cursor->up_match >= n_uniq && !page_rec_is_supremum(rec)) {
|
||||
*offsets = rec_get_offsets(rec, cursor->index, *offsets,
|
||||
|
@ -2349,11 +2351,13 @@ duplicate:
|
|||
}
|
||||
}
|
||||
|
||||
err = DB_SUCCESS;
|
||||
|
||||
if (cursor->up_match >= n_unique) {
|
||||
|
||||
rec = page_rec_get_next(btr_cur_get_rec(cursor));
|
||||
|
||||
if (!page_rec_is_supremum(rec)) {
|
||||
if (rec && !page_rec_is_supremum(rec)) {
|
||||
offsets = rec_get_offsets(rec, cursor->index, offsets,
|
||||
cursor->index->n_core_fields,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
@ -2378,24 +2382,23 @@ duplicate:
|
|||
}
|
||||
|
||||
switch (err) {
|
||||
case DB_SUCCESS_LOCKED_REC:
|
||||
case DB_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (row_ins_dupl_error_with_rec(
|
||||
rec, entry, cursor->index, offsets)) {
|
||||
goto duplicate;
|
||||
break;
|
||||
case DB_SUCCESS_LOCKED_REC:
|
||||
err = DB_SUCCESS;
|
||||
/* fall through */
|
||||
case DB_SUCCESS:
|
||||
if (row_ins_dupl_error_with_rec(
|
||||
rec, entry, cursor->index,
|
||||
offsets)) {
|
||||
goto duplicate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This should never happen */
|
||||
ut_error;
|
||||
err = DB_CORRUPTION;
|
||||
}
|
||||
|
||||
err = DB_SUCCESS;
|
||||
func_exit:
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
|
|
|
@ -1971,10 +1971,14 @@ corrupted_metadata:
|
|||
|
||||
mem_heap_empty(row_heap);
|
||||
|
||||
page_cur_move_to_next(cur);
|
||||
|
||||
stage->n_pk_recs_inc();
|
||||
|
||||
if (!page_cur_move_to_next(cur)) {
|
||||
corrupted_rec:
|
||||
err = DB_CORRUPTION;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (page_cur_is_after_last(cur)) {
|
||||
|
||||
stage->inc();
|
||||
|
@ -2080,9 +2084,10 @@ end_of_index:
|
|||
btr_leaf_page_release(page_cur_get_block(cur),
|
||||
BTR_SEARCH_LEAF, &mtr);
|
||||
page_cur_set_before_first(block, cur);
|
||||
page_cur_move_to_next(cur);
|
||||
|
||||
ut_ad(!page_cur_is_after_last(cur));
|
||||
if (!page_cur_move_to_next(cur)
|
||||
|| page_cur_is_after_last(cur)) {
|
||||
goto corrupted_rec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1804,7 +1804,11 @@ rec_loop:
|
|||
search result set, resulting in the phantom problem. */
|
||||
|
||||
if (!node->read_view) {
|
||||
rec_t* next_rec = page_rec_get_next(rec);
|
||||
const rec_t* next_rec = page_rec_get_next_const(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,
|
||||
|
@ -3425,11 +3429,13 @@ Row_sel_get_clust_rec_for_mysql::operator()(
|
|||
rec, sec_index, true,
|
||||
sec_index->n_fields, heap);
|
||||
page_cur_t page_cursor;
|
||||
|
||||
ulint low_match = page_cur_search(
|
||||
block, sec_index, tuple,
|
||||
PAGE_CUR_LE, &page_cursor);
|
||||
|
||||
ulint up_match = 0, low_match = 0;
|
||||
ut_ad(!page_cur_search_with_match(block, sec_index,
|
||||
tuple, PAGE_CUR_LE,
|
||||
&up_match,
|
||||
&low_match,
|
||||
&page_cursor,
|
||||
nullptr));
|
||||
ut_ad(low_match < dtuple_get_n_fields_cmp(tuple));
|
||||
mem_heap_free(heap);
|
||||
clust_rec = NULL;
|
||||
|
@ -4770,6 +4776,7 @@ wait_table_again:
|
|||
pcur, 0, &mtr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
page_corrupted:
|
||||
rec = NULL;
|
||||
goto page_read_error;
|
||||
}
|
||||
|
@ -4787,6 +4794,10 @@ wait_table_again:
|
|||
/* 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);
|
||||
if (UNIV_UNLIKELY(!next_rec)) {
|
||||
err = DB_CORRUPTION;
|
||||
goto page_corrupted;
|
||||
}
|
||||
|
||||
offsets = rec_get_offsets(next_rec, index, offsets,
|
||||
index->n_core_fields,
|
||||
|
@ -5792,8 +5803,8 @@ next_rec_after_check:
|
|||
if (err != DB_SUCCESS) {
|
||||
goto lock_wait_or_error;
|
||||
}
|
||||
} else {
|
||||
btr_pcur_move_to_next_on_page(pcur);
|
||||
} else if (!btr_pcur_move_to_next_on_page(pcur)) {
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
goto rec_loop;
|
||||
|
@ -5803,6 +5814,7 @@ next_rec_after_check:
|
|||
goto rec_loop;
|
||||
}
|
||||
if (UNIV_UNLIKELY(!btr_pcur_get_rec(pcur))) {
|
||||
corrupted:
|
||||
err = DB_CORRUPTION;
|
||||
goto normal_return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue