Commit 614395bc authored by Annamalai Gurusami's avatar Annamalai Gurusami

Bug #16806366 BOGUS CALL TO LOCK_REC_RESTORE_FROM_PAGE_INFIMUM IN

INSERT BUFFER MERGE

Problem:

When the record is merged from the change buffer to the actual page,
in a particular condition, it is assumed that the deleted rec will
be re-used by the inserted rec.  With this assumption the lock is
restored on the pointer to the deleted rec itself, thinking that
it is pointing to the newly inserted rec.

Solution:

Just before restoring the lock, update the rec pointer to point
to the newly inserted record.  An assert has been added to verify
this.  This assert will fail without the fix and will pass with
the fix.

rb#2449 in review by Marko and Jimmy
parent 1d3a200b
/*****************************************************************************
Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/****************************************************** /******************************************************
Insert buffer Insert buffer
...@@ -29,6 +47,7 @@ Created 7/19/1997 Heikki Tuuri ...@@ -29,6 +47,7 @@ Created 7/19/1997 Heikki Tuuri
#include "lock0lock.h" #include "lock0lock.h"
#include "log0recv.h" #include "log0recv.h"
#include "que0que.h" #include "que0que.h"
#include "rem0cmp.h"
/* STRUCTURE OF AN INSERT BUFFER RECORD /* STRUCTURE OF AN INSERT BUFFER RECORD
...@@ -2837,9 +2856,10 @@ ibuf_insert( ...@@ -2837,9 +2856,10 @@ ibuf_insert(
During merge, inserts to an index page a secondary index entry extracted During merge, inserts to an index page a secondary index entry extracted
from the insert buffer. */ from the insert buffer. */
static static
void rec_t*
ibuf_insert_to_index_page_low( ibuf_insert_to_index_page_low(
/*==========================*/ /*==========================*/
/* out: newly inserted record */
dtuple_t* entry, /* in: buffered entry to insert */ dtuple_t* entry, /* in: buffered entry to insert */
page_t* page, /* in: index page where the buffered entry page_t* page, /* in: index page where the buffered entry
should be placed */ should be placed */
...@@ -2852,10 +2872,13 @@ ibuf_insert_to_index_page_low( ...@@ -2852,10 +2872,13 @@ ibuf_insert_to_index_page_low(
ulint page_no; ulint page_no;
page_t* bitmap_page; page_t* bitmap_page;
ulint old_bits; ulint old_bits;
rec_t* rec;
DBUG_ENTER("ibuf_insert_to_index_page_low");
if (UNIV_LIKELY rec = page_cur_tuple_insert(page_cur, entry, index, mtr);
(page_cur_tuple_insert(page_cur, entry, index, mtr) != NULL)) {
return; if (rec != NULL) {
DBUG_RETURN(rec);
} }
/* If the record did not fit, reorganize */ /* If the record did not fit, reorganize */
...@@ -2866,9 +2889,10 @@ ibuf_insert_to_index_page_low( ...@@ -2866,9 +2889,10 @@ ibuf_insert_to_index_page_low(
/* This time the record must fit */ /* This time the record must fit */
if (UNIV_LIKELY rec = page_cur_tuple_insert(page_cur, entry, index, mtr);
(page_cur_tuple_insert(page_cur, entry, index, mtr) != NULL)) {
return; if (rec != NULL) {
DBUG_RETURN(rec);
} }
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -2897,6 +2921,8 @@ ibuf_insert_to_index_page_low( ...@@ -2897,6 +2921,8 @@ ibuf_insert_to_index_page_low(
fputs("InnoDB: Submit a detailed bug report" fputs("InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr); " to http://bugs.mysql.com\n", stderr);
DBUG_RETURN(NULL);
} }
/************************************************************************ /************************************************************************
...@@ -2916,6 +2942,8 @@ ibuf_insert_to_index_page( ...@@ -2916,6 +2942,8 @@ ibuf_insert_to_index_page(
ulint low_match; ulint low_match;
rec_t* rec; rec_t* rec;
DBUG_ENTER("ibuf_insert_to_index_page");
ut_ad(ibuf_inside()); ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
ut_ad(!buf_block_align(page)->is_hashed); ut_ad(!buf_block_align(page)->is_hashed);
...@@ -2950,7 +2978,7 @@ dump: ...@@ -2950,7 +2978,7 @@ dump:
"InnoDB: Submit a detailed bug report to" "InnoDB: Submit a detailed bug report to"
" http://bugs.mysql.com!\n", stderr); " http://bugs.mysql.com!\n", stderr);
return; DBUG_VOID_RETURN;
} }
low_match = page_cur_search(page, index, entry, low_match = page_cur_search(page, index, entry,
...@@ -2981,7 +3009,7 @@ dump: ...@@ -2981,7 +3009,7 @@ dump:
btr_cur_set_deleted_flag_for_ibuf(rec, FALSE, mtr); btr_cur_set_deleted_flag_for_ibuf(rec, FALSE, mtr);
updated_in_place: updated_in_place:
mem_heap_free(heap); mem_heap_free(heap);
return; DBUG_VOID_RETURN;
} }
/* Copy the info bits. Clear the delete-mark. */ /* Copy the info bits. Clear the delete-mark. */
...@@ -3021,15 +3049,21 @@ updated_in_place: ...@@ -3021,15 +3049,21 @@ updated_in_place:
lock_rec_store_on_page_infimum(page, rec); lock_rec_store_on_page_infimum(page, rec);
page_cur_delete_rec(&page_cur, index, offsets, mtr); page_cur_delete_rec(&page_cur, index, offsets, mtr);
page_cur_move_to_prev(&page_cur); page_cur_move_to_prev(&page_cur);
mem_heap_free(heap);
ibuf_insert_to_index_page_low(entry, page, index, mtr, rec = ibuf_insert_to_index_page_low(entry, page, index, mtr,
&page_cur); &page_cur);
ut_ad(!cmp_dtuple_rec(entry, rec,
rec_get_offsets(rec, index, NULL,
ULINT_UNDEFINED,
&heap)));
mem_heap_free(heap);
lock_rec_restore_from_page_infimum(rec, page); lock_rec_restore_from_page_infimum(rec, page);
} else { } else {
ibuf_insert_to_index_page_low(entry, page, index, mtr, ibuf_insert_to_index_page_low(entry, page, index, mtr,
&page_cur); &page_cur);
} }
DBUG_VOID_RETURN;
} }
/************************************************************************* /*************************************************************************
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -56,6 +56,7 @@ Created 7/19/1997 Heikki Tuuri ...@@ -56,6 +56,7 @@ Created 7/19/1997 Heikki Tuuri
#include "lock0lock.h" #include "lock0lock.h"
#include "log0recv.h" #include "log0recv.h"
#include "que0que.h" #include "que0que.h"
#include "rem0cmp.h"
/* STRUCTURE OF AN INSERT BUFFER RECORD /* STRUCTURE OF AN INSERT BUFFER RECORD
...@@ -2890,11 +2891,13 @@ do_insert: ...@@ -2890,11 +2891,13 @@ do_insert:
/********************************************************************//** /********************************************************************//**
During merge, inserts to an index page a secondary index entry extracted During merge, inserts to an index page a secondary index entry extracted
from the insert buffer. */ from the insert buffer.
@return newly inserted record */
static static
void rec_t*
ibuf_insert_to_index_page_low( ibuf_insert_to_index_page_low(
/*==========================*/ /*==========================*/
/* out: newly inserted record */
const dtuple_t* entry, /*!< in: buffered entry to insert */ const dtuple_t* entry, /*!< in: buffered entry to insert */
buf_block_t* block, /*!< in/out: index page where the buffered buf_block_t* block, /*!< in/out: index page where the buffered
entry should be placed */ entry should be placed */
...@@ -2909,10 +2912,12 @@ ibuf_insert_to_index_page_low( ...@@ -2909,10 +2912,12 @@ ibuf_insert_to_index_page_low(
ulint zip_size; ulint zip_size;
const page_t* bitmap_page; const page_t* bitmap_page;
ulint old_bits; ulint old_bits;
rec_t* rec;
DBUG_ENTER("ibuf_insert_to_index_page_low");
if (UNIV_LIKELY rec = page_cur_tuple_insert(page_cur, entry, index, 0, mtr);
(page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) { if (rec != NULL) {
return; DBUG_RETURN(rec);
} }
/* If the record did not fit, reorganize */ /* If the record did not fit, reorganize */
...@@ -2922,9 +2927,9 @@ ibuf_insert_to_index_page_low( ...@@ -2922,9 +2927,9 @@ ibuf_insert_to_index_page_low(
/* This time the record must fit */ /* This time the record must fit */
if (UNIV_LIKELY rec = page_cur_tuple_insert(page_cur, entry, index, 0, mtr);
(page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) { if (rec != NULL) {
return; DBUG_RETURN(rec);
} }
page = buf_block_get_frame(block); page = buf_block_get_frame(block);
...@@ -2957,6 +2962,7 @@ ibuf_insert_to_index_page_low( ...@@ -2957,6 +2962,7 @@ ibuf_insert_to_index_page_low(
fputs("InnoDB: Submit a detailed bug report" fputs("InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr); " to http://bugs.mysql.com\n", stderr);
DBUG_RETURN(NULL);
} }
/************************************************************************ /************************************************************************
...@@ -2976,6 +2982,7 @@ ibuf_insert_to_index_page( ...@@ -2976,6 +2982,7 @@ ibuf_insert_to_index_page(
ulint low_match; ulint low_match;
page_t* page = buf_block_get_frame(block); page_t* page = buf_block_get_frame(block);
rec_t* rec; rec_t* rec;
DBUG_ENTER("ibuf_insert_to_index_page");
ut_ad(ibuf_inside()); ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
...@@ -3011,7 +3018,7 @@ dump: ...@@ -3011,7 +3018,7 @@ dump:
"InnoDB: Submit a detailed bug report to" "InnoDB: Submit a detailed bug report to"
" http://bugs.mysql.com!\n", stderr); " http://bugs.mysql.com!\n", stderr);
return; DBUG_VOID_RETURN;
} }
low_match = page_cur_search(block, index, entry, low_match = page_cur_search(block, index, entry,
...@@ -3046,7 +3053,7 @@ dump: ...@@ -3046,7 +3053,7 @@ dump:
rec, page_zip, FALSE, mtr); rec, page_zip, FALSE, mtr);
updated_in_place: updated_in_place:
mem_heap_free(heap); mem_heap_free(heap);
return; DBUG_VOID_RETURN;
} }
/* Copy the info bits. Clear the delete-mark. */ /* Copy the info bits. Clear the delete-mark. */
...@@ -3090,15 +3097,21 @@ updated_in_place: ...@@ -3090,15 +3097,21 @@ updated_in_place:
lock_rec_store_on_page_infimum(block, rec); lock_rec_store_on_page_infimum(block, rec);
page_cur_delete_rec(&page_cur, index, offsets, mtr); page_cur_delete_rec(&page_cur, index, offsets, mtr);
page_cur_move_to_prev(&page_cur); page_cur_move_to_prev(&page_cur);
rec = ibuf_insert_to_index_page_low(entry, block, index, mtr,
&page_cur);
ut_ad(!cmp_dtuple_rec(entry, rec,
rec_get_offsets(rec, index, NULL,
ULINT_UNDEFINED,
&heap)));
mem_heap_free(heap); mem_heap_free(heap);
ibuf_insert_to_index_page_low(entry, block, index, mtr,
&page_cur);
lock_rec_restore_from_page_infimum(block, rec, block); lock_rec_restore_from_page_infimum(block, rec, block);
} else { } else {
ibuf_insert_to_index_page_low(entry, block, index, mtr, ibuf_insert_to_index_page_low(entry, block, index, mtr,
&page_cur); &page_cur);
} }
DBUG_VOID_RETURN;
} }
/*********************************************************************//** /*********************************************************************//**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment