summaryrefslogtreecommitdiffstats
path: root/storage/innobase/btr/btr0cur.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--storage/innobase/btr/btr0cur.cc107
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();