diff options
Diffstat (limited to 'storage/xtradb/btr')
-rw-r--r-- | storage/xtradb/btr/btr0btr.c | 70 | ||||
-rw-r--r-- | storage/xtradb/btr/btr0cur.c | 45 | ||||
-rw-r--r-- | storage/xtradb/btr/btr0pcur.c | 67 |
3 files changed, 121 insertions, 61 deletions
diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c index 75cc80d0967..75be76b9dd1 100644 --- a/storage/xtradb/btr/btr0btr.c +++ b/storage/xtradb/btr/btr0btr.c @@ -664,6 +664,12 @@ btr_root_fseg_validate( { ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET); + if (UNIV_UNLIKELY(srv_pass_corrupt_table)) { + return (mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space) + && (offset >= FIL_PAGE_DATA) + && (offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END); + } + ut_a(mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space); ut_a(offset >= FIL_PAGE_DATA); ut_a(offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END); @@ -704,6 +710,17 @@ btr_root_block_get( if (!dict_index_is_ibuf(index)) { const page_t* root = buf_block_get_frame(block); + if (UNIV_UNLIKELY(srv_pass_corrupt_table)) { + if (!btr_root_fseg_validate(FIL_PAGE_DATA + + PAGE_BTR_SEG_LEAF + + root, space)) + return(NULL); + if (!btr_root_fseg_validate(FIL_PAGE_DATA + + PAGE_BTR_SEG_TOP + + root, space)) + return(NULL); + return(block); + } ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + root, space)); ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP @@ -1852,6 +1869,7 @@ btr_root_raise_and_insert( root = btr_cur_get_page(cursor); root_block = btr_cur_get_block(cursor); root_page_zip = buf_block_get_page_zip(root_block); + ut_ad(page_get_n_recs(root) > 0); #ifdef UNIV_ZIP_DEBUG ut_a(!root_page_zip || page_zip_validate(root_page_zip, root)); #endif /* UNIV_ZIP_DEBUG */ @@ -2332,12 +2350,20 @@ btr_insert_on_non_leaf_level_func( BTR_CONT_MODIFY_TREE, &cursor, 0, file, line, mtr); - err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG - | BTR_KEEP_SYS_FLAG - | BTR_NO_UNDO_LOG_FLAG, - &cursor, tuple, &rec, - &dummy_big_rec, 0, NULL, mtr); - ut_a(err == DB_SUCCESS); + ut_ad(cursor.flag == BTR_CUR_BINARY); + + err = btr_cur_optimistic_insert( + BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG + | BTR_NO_UNDO_LOG_FLAG, &cursor, tuple, &rec, + &dummy_big_rec, 0, NULL, mtr); + + if (err == DB_FAIL) { + err = btr_cur_pessimistic_insert( + BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG + | BTR_NO_UNDO_LOG_FLAG, + &cursor, tuple, &rec, &dummy_big_rec, 0, NULL, mtr); + ut_a(err == DB_SUCCESS); + } } /**************************************************************//** @@ -3262,6 +3288,7 @@ btr_compress( if (adjust) { nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); + ut_ad(nth_rec > 0); } /* Decide the page to which we try to merge and which will inherit @@ -3497,6 +3524,7 @@ func_exit: mem_heap_free(heap); if (adjust) { + ut_ad(nth_rec > 0); btr_cur_position( index, page_rec_get_nth(merge_block->frame, nth_rec), @@ -4009,8 +4037,22 @@ btr_index_page_validate( { page_cur_t cur; ibool ret = TRUE; +#ifndef DBUG_OFF + ulint nth = 1; +#endif /* !DBUG_OFF */ page_cur_set_before_first(block, &cur); + + /* Directory slot 0 should only contain the infimum record. */ + DBUG_EXECUTE_IF("check_table_rec_next", + ut_a(page_rec_get_nth_const( + page_cur_get_page(&cur), 0) + == cur.rec); + ut_a(page_dir_slot_get_n_owned( + page_dir_get_nth_slot( + page_cur_get_page(&cur), 0)) + == 1);); + page_cur_move_to_next(&cur); for (;;) { @@ -4024,6 +4066,16 @@ btr_index_page_validate( return(FALSE); } + /* Verify that page_rec_get_nth_const() is correctly + retrieving each record. */ + DBUG_EXECUTE_IF("check_table_rec_next", + ut_a(cur.rec == page_rec_get_nth_const( + page_cur_get_page(&cur), + page_rec_get_n_recs_before( + cur.rec))); + ut_a(nth++ == page_rec_get_n_recs_before( + cur.rec));); + page_cur_move_to_next(&cur); } @@ -4435,6 +4487,12 @@ btr_validate_index( mtr_x_lock(dict_index_get_lock(index), &mtr); root = btr_root_get(index, &mtr); + + if (UNIV_UNLIKELY(srv_pass_corrupt_table && !root)) { + mtr_commit(&mtr); + return(FALSE); + } + n = btr_page_get_level(root, &mtr); for (i = 0; i <= n && !trx_is_interrupted(trx); i++) { diff --git a/storage/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c index 4161be93a90..91f14beab96 100644 --- a/storage/xtradb/btr/btr0cur.c +++ b/storage/xtradb/btr/btr0cur.c @@ -1307,7 +1307,12 @@ fail_err: if (UNIV_UNLIKELY(reorg)) { ut_a(zip_size); - ut_a(*rec); + /* It's possible for rec to be NULL if the + page is compressed. This is because a + reorganized page may become incompressible. */ + if (!*rec) { + goto fail; + } } } @@ -1443,20 +1448,9 @@ btr_cur_pessimistic_insert( ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); - /* Try first an optimistic insert; reset the cursor flag: we do not - assume anything of how it was positioned */ - cursor->flag = BTR_CUR_BINARY; - err = btr_cur_optimistic_insert(flags, cursor, entry, rec, - big_rec, n_ext, thr, mtr); - if (err != DB_FAIL) { - - return(err); - } - - /* Retry with a pessimistic insert. Check locks and write to undo log, - if specified */ + /* Check locks and write to undo log, if specified */ err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, mtr, &dummy_inh); @@ -2083,8 +2077,12 @@ any_extern: goto err_exit; } - max_size = old_rec_size - + page_get_max_insert_size_after_reorganize(page, 1); + /* We do not attempt to reorganize if the page is compressed. + This is because the page may fail to compress after reorganization. */ + max_size = page_zip + ? page_get_max_insert_size(page, 1) + : (old_rec_size + + page_get_max_insert_size_after_reorganize(page, 1)); if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT) && (max_size >= new_rec_size)) @@ -2452,7 +2450,12 @@ make_external: err = DB_SUCCESS; goto return_after_reservations; } else { - ut_a(optim_err != DB_UNDERFLOW); + /* If the page is compressed and it initially + compresses very well, and there is a subsequent insert + of a badly-compressing record, it is possible for + btr_cur_optimistic_update() to return DB_UNDERFLOW and + btr_cur_insert_if_possible() to return FALSE. */ + ut_a(page_zip || optim_err != DB_UNDERFLOW); /* Out of space: reset the free bits. */ if (!dict_index_is_clust(index) @@ -2480,8 +2483,10 @@ make_external: record on its page? */ was_first = page_cur_is_before_first(page_cursor); - /* The first parameter means that no lock checking and undo logging - is made in the insert */ + /* Lock checks and undo logging were already performed by + btr_cur_upd_lock_and_undo(). We do not try + btr_cur_optimistic_insert() because + btr_cur_insert_if_possible() already failed above. */ err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG @@ -3483,6 +3488,8 @@ btr_estimate_n_rows_in_range( n_rows = n_rows * 2; } + DBUG_EXECUTE_IF("bug14007649", return(n_rows);); + /* Do not estimate the number of rows in the range to over 1 / 2 of the estimated rows in the whole table */ @@ -3582,9 +3589,9 @@ btr_record_not_null_field_in_rec( for (i = 0; i < n_unique; i++) { if (rec_offs_nth_sql_null(offsets, i)) { - /* Break if we hit the first NULL value */ break; } + n_not_null[i]++; } } diff --git a/storage/xtradb/btr/btr0pcur.c b/storage/xtradb/btr/btr0pcur.c index be1a6cbd8ee..f5323adec91 100644 --- a/storage/xtradb/btr/btr0pcur.c +++ b/storage/xtradb/btr/btr0pcur.c @@ -342,44 +342,39 @@ btr_pcur_restore_position_func( /* Restore the old search mode */ cursor->search_mode = old_mode; - if (btr_pcur_is_on_user_rec(cursor)) { - switch (cursor->rel_pos) { - case BTR_PCUR_ON: - if (!cmp_dtuple_rec( - tuple, btr_pcur_get_rec(cursor), - rec_get_offsets(btr_pcur_get_rec(cursor), - index, NULL, - ULINT_UNDEFINED, &heap))) { - - /* We have to store the NEW value for - the modify clock, since the cursor can - now be on a different page! But we can - retain the value of old_rec */ - - cursor->block_when_stored = - btr_pcur_get_block(cursor); - cursor->modify_clock = - buf_block_get_modify_clock( - cursor->block_when_stored); - cursor->old_stored = BTR_PCUR_OLD_STORED; - - mem_heap_free(heap); - - return(TRUE); - } - - break; - case BTR_PCUR_BEFORE: - page_cur_move_to_next(btr_pcur_get_page_cur(cursor)); - break; - case BTR_PCUR_AFTER: - page_cur_move_to_prev(btr_pcur_get_page_cur(cursor)); - break; + switch (cursor->rel_pos) { + case BTR_PCUR_ON: + if (btr_pcur_is_on_user_rec(cursor) + && !cmp_dtuple_rec( + tuple, btr_pcur_get_rec(cursor), + rec_get_offsets(btr_pcur_get_rec(cursor), + index, NULL, + ULINT_UNDEFINED, &heap))) { + + /* We have to store the NEW value for + the modify clock, since the cursor can + now be on a different page! But we can + retain the value of old_rec */ + + cursor->block_when_stored = + btr_pcur_get_block(cursor); + cursor->modify_clock = + buf_block_get_modify_clock( + cursor->block_when_stored); + cursor->old_stored = BTR_PCUR_OLD_STORED; + + mem_heap_free(heap); + + return(TRUE); + } #ifdef UNIV_DEBUG - default: - ut_error; + /* fall through */ + case BTR_PCUR_BEFORE: + case BTR_PCUR_AFTER: + break; + default: + ut_error; #endif /* UNIV_DEBUG */ - } } mem_heap_free(heap); |