List:Commits« Previous MessageNext Message »
From:marko.makela Date:April 21 2010 6:54pm
Subject:bzr commit into mysql-5.1-innodb branch (marko.makela:3413) Bug#52964
View as plain text  
#At file:///home/marko/innobase/dev/mysql/5.1-innodb/ based on revid:marko.makela@strippedzbyu0ekj5d

 3413 Marko Mäkelä	2010-04-21
      btr_page_split_and_insert(): Avoid an infinite loop. (Bug #52964)
      
      btr_page_tuple_smaller(): New function, refactored from
      btr_page_split_and_insert().
      
      btr_page_get_split_rec(): Renamed from btr_page_get_sure_split_rec().
      Note that a NULL return may mean that the tuple is to be inserted into
      either the lower or upper page, to be determined by btr_page_tuple_smaller().
      
      btr_page_split_and_insert(): When btr_page_get_split_rec() returns NULL,
      invoke btr_page_tuple_smaller() to determine which half-page the tuple
      belongs to.
      
      Reviewed by Sunny Bains

    modified:
      storage/innodb_plugin/ChangeLog
      storage/innodb_plugin/btr/btr0btr.c
=== modified file 'storage/innodb_plugin/ChangeLog'
--- a/storage/innodb_plugin/ChangeLog	2010-04-21 10:27:23 +0000
+++ b/storage/innodb_plugin/ChangeLog	2010-04-21 18:53:59 +0000
@@ -1,5 +1,11 @@
 2010-04-21	The InnoDB Team
 
+	* btr/btr0btr.c:
+	Fix Bug#52964 Infinite loop in btr_page_split_and_insert()
+	in ROW_FORMAT=COMPRESSED
+
+2010-04-21	The InnoDB Team
+
 	* data/data0data.c:
 	Fix Bug#52745 Failing assertion: blob_no < page_zip->n_blobs
 

=== modified file 'storage/innodb_plugin/btr/btr0btr.c'
--- a/storage/innodb_plugin/btr/btr0btr.c	2010-04-20 08:29:08 +0000
+++ b/storage/innodb_plugin/btr/btr0btr.c	2010-04-21 18:53:59 +0000
@@ -1451,11 +1451,11 @@ Calculates a split record such that the
 its half-page when the split is performed. We assume in this function
 only that the cursor page has at least one user record.
 @return split record, or NULL if tuple will be the first record on
-upper half-page */
+the lower or upper half-page (determined by btr_page_tuple_smaller()) */
 static
 rec_t*
-btr_page_get_sure_split_rec(
-/*========================*/
+btr_page_get_split_rec(
+/*===================*/
 	btr_cur_t*	cursor,	/*!< in: cursor at which insert should be made */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext)	/*!< in: number of externally stored columns */
@@ -1832,6 +1832,37 @@ btr_attach_half_pages(
 }
 
 /*************************************************************//**
+Determine if a tuple is smaller than any record on the page.
+@return TRUE if smaller */
+static
+ibool
+btr_page_tuple_smaller(
+/*===================*/
+	btr_cur_t*	cursor,	/*!< in: b-tree cursor */
+	const dtuple_t*	tuple,	/*!< in: tuple to consider */
+	ulint*		offsets,/*!< in/out: temporary storage */
+	ulint		n_uniq,	/*!< in: number of unique fields
+				in the index page records */
+	mem_heap_t**	heap)	/*!< in/out: heap for offsets */
+{
+	buf_block_t*	block;
+	const rec_t*	first_rec;
+	page_cur_t	pcur;
+
+	/* Read the first user record in the page. */
+	block = btr_cur_get_block(cursor);
+	page_cur_set_before_first(block, &pcur);
+	page_cur_move_to_next(&pcur);
+	first_rec = page_cur_get_rec(&pcur);
+
+	offsets = rec_get_offsets(
+		first_rec, cursor->index, offsets,
+		n_uniq, heap);
+
+	return(cmp_dtuple_rec(tuple, first_rec, offsets) < 0);
+}
+
+/*************************************************************//**
 Splits an index page to halves and inserts the tuple. It is assumed
 that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is
 released within this function! NOTE that the operation of this
@@ -1905,49 +1936,45 @@ func_start:
 	if (n_iterations > 0) {
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
-		split_rec = btr_page_get_sure_split_rec(cursor, tuple, n_ext);
+		split_rec = btr_page_get_split_rec(cursor, tuple, n_ext);
 
+		if (UNIV_UNLIKELY(split_rec == NULL)) {
+			insert_left = btr_page_tuple_smaller(
+				cursor, tuple, offsets, n_uniq, &heap);
+		}
 	} else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
+		insert_left = FALSE;
 
 	} else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {
 		direction = FSP_DOWN;
 		hint_page_no = page_no - 1;
+		ut_ad(split_rec);
 	} else {
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
 
-		if (page_get_n_recs(page) == 1) {
-			page_cur_t	pcur;
+		/* If there is only one record in the index page, we
+		can't split the node in the middle by default. We need
+		to determine whether the new record will be inserted
+		to the left or right. */
 
-			/* There is only one record in the index page
-			therefore we can't split the node in the middle
-			by default. We need to determine whether the
-			new record will be inserted to the left or right. */
-
-			/* Read the first (and only) record in the page. */
-			page_cur_set_before_first(block, &pcur);
-			page_cur_move_to_next(&pcur);
-			first_rec = page_cur_get_rec(&pcur);
-
-			offsets = rec_get_offsets(
-				first_rec, cursor->index, offsets,
-				n_uniq, &heap);
-
-			/* If the new record is less than the existing record
-			the split in the middle will copy the existing
-			record to the new node. */
-			if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) {
-				split_rec = page_get_middle_rec(page);
-			} else {
-				split_rec = NULL;
-			}
-		} else {
+		if (page_get_n_recs(page) > 1) {
 			split_rec = page_get_middle_rec(page);
+		} else if (btr_page_tuple_smaller(cursor, tuple,
+						  offsets, n_uniq, &heap)) {
+			split_rec = page_rec_get_next(
+				page_get_infimum_rec(page));
+		} else {
+			split_rec = NULL;
+			insert_left = FALSE;
 		}
 	}
 
+	/* At this point, insert_left is initialized if split_rec == NULL
+	and may be uninitialized otherwise. */
+
 	/* 2. Allocate a new page to the index */
 	new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
 				   btr_page_get_level(page, mtr), mtr);
@@ -1974,11 +2001,11 @@ func_start:
 			avoid further splits by inserting the record
 			to an empty page. */
 			split_rec = NULL;
-			goto insert_right;
+			goto insert_empty;
 		}
 	} else {
-insert_right:
-		insert_left = FALSE;
+insert_empty:
+		ut_ad(!split_rec);
 		buf = mem_alloc(rec_get_converted_size(cursor->index,
 						       tuple, n_ext));
 

Attachment: [text/bzr-bundle] bzr/marko.makela@oracle.com-20100421185359-8qaxoa2yyrpzwdd7.bundle
Thread
bzr commit into mysql-5.1-innodb branch (marko.makela:3413) Bug#52964marko.makela21 Apr