diff options
Diffstat (limited to 'storage/innobase/page/page0page.cc')
-rw-r--r-- | storage/innobase/page/page0page.cc | 375 |
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; + } } |