summaryrefslogtreecommitdiff
path: root/storage/innobase/page/page0page.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/page/page0page.cc')
-rw-r--r--storage/innobase/page/page0page.cc375
1 files changed, 226 insertions, 149 deletions
diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc
index de92c539444..3d4aaf9111f 100644
--- a/storage/innobase/page/page0page.cc
+++ b/storage/innobase/page/page0page.cc
@@ -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);
- if (page_is_comp(page)) {
- while (rec_get_n_owned_new(rec) == 0) {
+ const page_t* const page = page_align(rec);
- rec = rec_get_next_ptr_const(rec, TRUE);
- n--;
- }
+ ut_ad(!page_rec_is_infimum(rec));
+
+ ulint slot_no = page_dir_find_owner_slot(rec);
- for (i = 0; ; i++) {
- slot = page_dir_get_nth_slot(page, i);
- slot_rec = page_dir_slot_get_rec(slot);
+ if (UNIV_UNLIKELY(!slot_no || slot_no == ULINT_UNDEFINED)) {
+ return nullptr;
+ }
- n += lint(rec_get_n_owned_new(slot_rec));
+ const page_dir_slot_t* slot = page_dir_get_nth_slot(page, slot_no - 1);
- if (rec == slot_rec) {
+ if (UNIV_UNLIKELY(!(rec2 = page_dir_slot_get_rec_validate(slot)))) {
+ return nullptr;
+ }
+ if (page_is_comp(page)) {
+ 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;
+ }
+ 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--;
+ 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;
}
+ }
+
+ return(prev_rec);
+}
- for (i = 0; ; i++) {
- slot = page_dir_get_nth_slot(page, i);
- slot_rec = page_dir_slot_get_rec(slot);
+/** 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);
- n += lint(rec_get_n_owned_old(slot_rec));
+ lint n= 0;
- if (rec == slot_rec) {
+ ut_ad(page_rec_check(rec));
- break;
- }
- }
- }
+ 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;
- n--;
+ 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));
- ut_ad(n >= 0);
- ut_ad((ulong) n < srv_page_size / (REC_N_NEW_EXTRA_BYTES + 1));
+ if (rec == slot_rec)
+ goto found;
+ }
+ while ((slot-= 2) > end_slot);
+ }
- return((ulint) n);
+ 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_last_not_deleted(
- const page_t* page)
+const rec_t *page_find_rec_last_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;
+ }
}