diff options
Diffstat (limited to '')
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 107 |
1 files changed, 66 insertions, 41 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 46afb73b..2fc05b06 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -817,7 +817,7 @@ static ulint btr_node_ptr_max_size(const dict_index_t* index) /* Determine the maximum length of the index field. */ field_max_size = dict_col_get_fixed_size(col, comp); - if (field_max_size) { + if (field_max_size && field->fixed_len) { /* dict_index_add_col() should guarantee this */ ut_ad(!field->prefix_len || field->fixed_len == field->prefix_len); @@ -935,7 +935,7 @@ static inline page_cur_mode_t btr_cur_nonleaf_mode(page_cur_mode_t mode) return PAGE_CUR_LE; } -static MY_ATTRIBUTE((nonnull)) +MY_ATTRIBUTE((nonnull,warn_unused_result)) /** Acquire a latch on the previous page without violating the latching order. @param block index page @param page_id page identifier with valid space identifier @@ -946,8 +946,9 @@ static MY_ATTRIBUTE((nonnull)) @retval 0 if an error occurred @retval 1 if the page could be latched in the wrong order @retval -1 if the latch on block was temporarily released */ -int btr_latch_prev(buf_block_t *block, page_id_t page_id, ulint zip_size, - rw_lock_type_t rw_latch, mtr_t *mtr, dberr_t *err) +static int btr_latch_prev(buf_block_t *block, page_id_t page_id, + ulint zip_size, + rw_lock_type_t rw_latch, mtr_t *mtr, dberr_t *err) { ut_ad(rw_latch == RW_S_LATCH || rw_latch == RW_X_LATCH); ut_ad(page_id.space() == block->page.id().space()); @@ -955,47 +956,80 @@ int btr_latch_prev(buf_block_t *block, page_id_t page_id, ulint zip_size, const auto prev_savepoint= mtr->get_savepoint(); ut_ad(block == mtr->at_savepoint(prev_savepoint - 1)); - page_id.set_page_no(btr_page_get_prev(block->page.frame)); + const page_t *const page= block->page.frame; + page_id.set_page_no(btr_page_get_prev(page)); + /* We are holding a latch on the current page. + + We will start by buffer-fixing the left sibling. Waiting for a latch + on it while holding a latch on the current page could lead to a + deadlock, because another thread could hold that latch and wait for + a right sibling page latch (the current page). + + If there is a conflict, we will temporarily release our latch on the + current block while waiting for a latch on the left sibling. The + buffer-fixes on both blocks will prevent eviction. */ + + retry: buf_block_t *prev= buf_page_get_gen(page_id, zip_size, RW_NO_LATCH, nullptr, BUF_GET, mtr, err, false); if (UNIV_UNLIKELY(!prev)) return 0; int ret= 1; - if (UNIV_UNLIKELY(rw_latch == RW_S_LATCH)) + static_assert(MTR_MEMO_PAGE_S_FIX == mtr_memo_type_t(BTR_SEARCH_LEAF), ""); + static_assert(MTR_MEMO_PAGE_X_FIX == mtr_memo_type_t(BTR_MODIFY_LEAF), ""); + + if (rw_latch == RW_S_LATCH + ? prev->page.lock.s_lock_try() : prev->page.lock.x_lock_try()) { - if (UNIV_LIKELY(prev->page.lock.s_lock_try())) + mtr->lock_register(prev_savepoint, mtr_memo_type_t(rw_latch)); + if (UNIV_UNLIKELY(prev->page.id() != page_id)) { - mtr->lock_register(prev_savepoint, MTR_MEMO_PAGE_S_FIX); - goto prev_latched; + fail: + /* the page was just read and found to be corrupted */ + mtr->rollback_to_savepoint(prev_savepoint); + return 0; } - block->page.lock.s_unlock(); } else { - if (UNIV_LIKELY(prev->page.lock.x_lock_try())) + ut_ad(mtr->at_savepoint(mtr->get_savepoint() - 1)->page.id() == page_id); + mtr->release_last_page(); + if (rw_latch == RW_S_LATCH) + block->page.lock.s_unlock(); + else + block->page.lock.x_unlock(); + + prev= buf_page_get_gen(page_id, zip_size, rw_latch, prev, + BUF_GET, mtr, err); + if (rw_latch == RW_S_LATCH) + block->page.lock.s_lock(); + else + block->page.lock.x_lock(); + + const page_id_t prev_page_id= page_id; + page_id.set_page_no(btr_page_get_prev(page)); + + if (UNIV_UNLIKELY(page_id != prev_page_id)) { - mtr->lock_register(prev_savepoint, MTR_MEMO_PAGE_X_FIX); - goto prev_latched; + mtr->release_last_page(); + if (page_id.page_no() == FIL_NULL) + return -1; + goto retry; } - block->page.lock.x_unlock(); + + if (UNIV_UNLIKELY(!prev)) + goto fail; + + ret= -1; } - ret= -1; - mtr->lock_register(prev_savepoint - 1, MTR_MEMO_BUF_FIX); - mtr->rollback_to_savepoint(prev_savepoint); - prev= buf_page_get_gen(page_id, zip_size, rw_latch, prev, - BUF_GET, mtr, err, false); - if (UNIV_UNLIKELY(!prev)) - return 0; - mtr->upgrade_buffer_fix(prev_savepoint - 1, rw_latch); - - prev_latched: - if (memcmp_aligned<2>(FIL_PAGE_TYPE + prev->page.frame, - FIL_PAGE_TYPE + block->page.frame, 2) || - memcmp_aligned<2>(PAGE_HEADER + PAGE_INDEX_ID + prev->page.frame, - PAGE_HEADER + PAGE_INDEX_ID + block->page.frame, 8) || - page_is_comp(prev->page.frame) != page_is_comp(block->page.frame)) + const page_t *const p= prev->page.frame; + if (memcmp_aligned<4>(FIL_PAGE_NEXT + p, FIL_PAGE_OFFSET + page, 4) || + memcmp_aligned<2>(FIL_PAGE_TYPE + p, FIL_PAGE_TYPE + page, 2) || + memcmp_aligned<2>(PAGE_HEADER + PAGE_INDEX_ID + p, + PAGE_HEADER + PAGE_INDEX_ID + page, 8) || + page_is_comp(p) != page_is_comp(page)) { ut_ad("corrupted" == 0); // FIXME: remove this *err= DB_CORRUPTION; @@ -6092,7 +6126,6 @@ btr_store_big_rec_extern_fields( for (ulint blob_npages = 0;; ++blob_npages) { buf_block_t* block; const ulint commit_freq = 4; - uint32_t r_extents; ut_ad(page_align(field_ref) == page_align(rec)); @@ -6127,22 +6160,14 @@ btr_store_big_rec_extern_fields( hint_prev = rec_block->page.id().page_no(); } - error = fsp_reserve_free_extents( - &r_extents, index->table->space, 1, - FSP_BLOB, &mtr, 1); - if (UNIV_UNLIKELY(error != DB_SUCCESS)) { -alloc_fail: - mtr.commit(); - goto func_exit; - } - block = btr_page_alloc(index, hint_prev + 1, FSP_NO_DIR, 0, &mtr, &mtr, &error); - index->table->space->release_free_extents(r_extents); if (!block) { - goto alloc_fail; +alloc_fail: + mtr.commit(); + goto func_exit; } const uint32_t space_id = block->page.id().space(); |