List:Commits« Previous MessageNext Message »
From:marko.makela Date:May 23 2012 8:52am
Subject:bzr push into mysql-trunk-wl6255 branch (marko.makela:3852 to 3855) WL#6255
View as plain text  
 3855 Marko Mäkelä	2012-05-23
      WL#6255 preparation: Do not recompute offsets after B-tree insert.
      
      btr_root_raise_and_insert(), btr_page_insert_fits(),
      btr_page_tuple_smaller(), btr_page_split_and_insert(),
      btr_cur_insert_if_possible(), btr_cur_optimistic_insert(),
      btr_cur_pessimistic_insert(), ibuf_insert_to_index_page_low(),
      page_cur_tuple_insert(), row_ins_sec_index_entry_by_modify():
      Add in/out parameters for offsets and heap.
      
      row_ins_sec_index_entry_low(): Add a parameter for heap.

    modified:
      storage/innobase/btr/btr0btr.cc
      storage/innobase/btr/btr0cur.cc
      storage/innobase/ibuf/ibuf0ibuf.cc
      storage/innobase/include/btr0btr.h
      storage/innobase/include/btr0cur.h
      storage/innobase/include/page0cur.h
      storage/innobase/include/page0cur.ic
      storage/innobase/row/row0ins.cc
      storage/innobase/row/row0log.cc
      storage/innobase/row/row0merge.cc
 3854 Marko Mäkelä	2012-05-23
      Add function attributes. Replace btr_page_get_level() with a macro.

    modified:
      storage/innobase/include/btr0btr.h
      storage/innobase/include/btr0btr.ic
 3853 Marko Mäkelä	2012-05-23
      WL#5526 optimization cleanup:
      
      row_log_online_op(): Fix a bogus warning on uninitialized mrec_size,
      and do a little less work while holding index->online_log->mutex.

    modified:
      storage/innobase/row/row0log.cc
 3852 Marko Mäkelä	2012-05-22
      Add function attributes.

    modified:
      storage/innobase/include/rem0rec.h
=== modified file 'storage/innobase/btr/btr0btr.cc'
--- a/storage/innobase/btr/btr0btr.cc	revid:marko.makela@stripped2gjq7ana
+++ b/storage/innobase/btr/btr0btr.cc	revid:marko.makela@stripped
@@ -1864,6 +1864,8 @@ btr_root_raise_and_insert(
 				on the root page; when the function returns,
 				the cursor is positioned on the predecessor
 				of the inserted record */
+	ulint**		offsets,/*!< out: offsets on inserted record */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr)	/*!< in: mtr */
@@ -1873,7 +1875,6 @@ btr_root_raise_and_insert(
 	page_t*		new_page;
 	ulint		new_page_no;
 	rec_t*		rec;
-	mem_heap_t*	heap;
 	dtuple_t*	node_ptr;
 	ulint		level;
 	rec_t*		node_ptr_rec;
@@ -1958,7 +1959,9 @@ btr_root_raise_and_insert(
 	lock_update_root_raise(new_block, root_block);
 
 	/* Create a memory heap where the node pointer is stored */
-	heap = mem_heap_create(100);
+	if (!*heap) {
+		*heap = mem_heap_create(1000);
+	}
 
 	rec = page_rec_get_next(page_get_infimum_rec(new_page));
 	new_page_no = buf_block_get_page_no(new_block);
@@ -1966,8 +1969,8 @@ btr_root_raise_and_insert(
 	/* Build the node pointer (= node key and page address) for the
 	child */
 
-	node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap,
-					     level);
+	node_ptr = dict_index_build_node_ptr(
+		index, rec, new_page_no, *heap, level);
 	/* The node pointer must be marked as the predefined minimum record,
 	as there is no lower alphabetical limit to records in the leftmost
 	node of a level: */
@@ -1993,15 +1996,12 @@ btr_root_raise_and_insert(
 	page_cur_set_before_first(root_block, page_cursor);
 
 	node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
-					     index, 0, mtr);
+					     index, offsets, heap, 0, mtr);
 
 	/* The root page should only contain the node pointer
 	to new_page at this point.  Thus, the data should fit. */
 	ut_a(node_ptr_rec);
 
-	/* Free the memory heap */
-	mem_heap_free(heap);
-
 	/* We play safe and reset the free bits for the new page */
 
 #if 0
@@ -2017,7 +2017,8 @@ btr_root_raise_and_insert(
 			PAGE_CUR_LE, page_cursor);
 
 	/* Split the child and insert tuple */
-	return(btr_page_split_and_insert(flags, cursor, tuple, n_ext, mtr));
+	return(btr_page_split_and_insert(flags, cursor, offsets, heap,
+					 tuple, n_ext, mtr));
 }
 
 /*************************************************************//**
@@ -2245,9 +2246,9 @@ func_exit:
 /*************************************************************//**
 Returns TRUE if the insert fits on the appropriate half-page with the
 chosen split_rec.
-@return	TRUE if fits */
-static
-ibool
+@return	true if fits */
+static __attribute__((nonnull(1,3,4,6), warn_unused_result))
+bool
 btr_page_insert_fits(
 /*=================*/
 	btr_cur_t*	cursor,	/*!< in: cursor at which insert
@@ -2255,11 +2256,11 @@ btr_page_insert_fits(
 	const rec_t*	split_rec,/*!< in: suggestion for first record
 				on upper half-page, or NULL if
 				tuple to be inserted should be first */
-	const ulint*	offsets,/*!< in: rec_get_offsets(
-				split_rec, cursor->index) */
+	ulint**		offsets,/*!< in: rec_get_offsets(
+				split_rec, cursor->index); out: garbage */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
-	mem_heap_t*	heap)	/*!< in: temporary memory heap */
+	mem_heap_t**	heap)	/*!< in: temporary memory heap */
 {
 	page_t*		page;
 	ulint		insert_size;
@@ -2268,15 +2269,13 @@ btr_page_insert_fits(
 	ulint		total_n_recs;
 	const rec_t*	rec;
 	const rec_t*	end_rec;
-	ulint*		offs;
 
 	page = btr_cur_get_page(cursor);
 
-	ut_ad(!split_rec == !offsets);
-	ut_ad(!offsets
-	      || !page_is_comp(page) == !rec_offs_comp(offsets));
-	ut_ad(!offsets
-	      || rec_offs_validate(split_rec, cursor->index, offsets));
+	ut_ad(!split_rec
+	      || !page_is_comp(page) == !rec_offs_comp(*offsets));
+	ut_ad(!split_rec
+	      || rec_offs_validate(split_rec, cursor->index, *offsets));
 
 	insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
 	free_space  = page_get_free_space_of_empty(page_is_comp(page));
@@ -2294,7 +2293,7 @@ btr_page_insert_fits(
 		rec = page_rec_get_next(page_get_infimum_rec(page));
 		end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
 
-	} else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
+	} else if (cmp_dtuple_rec(tuple, split_rec, *offsets) >= 0) {
 
 		rec = page_rec_get_next(page_get_infimum_rec(page));
 		end_rec = split_rec;
@@ -2309,19 +2308,17 @@ btr_page_insert_fits(
 		/* Ok, there will be enough available space on the
 		half page where the tuple is inserted */
 
-		return(TRUE);
+		return(true);
 	}
 
-	offs = NULL;
-
 	while (rec != end_rec) {
 		/* In this loop we calculate the amount of reserved
 		space after rec is removed from page. */
 
-		offs = rec_get_offsets(rec, cursor->index, offs,
-				       ULINT_UNDEFINED, &heap);
+		*offsets = rec_get_offsets(rec, cursor->index, *offsets,
+					   ULINT_UNDEFINED, heap);
 
-		total_data -= rec_offs_size(offs);
+		total_data -= rec_offs_size(*offsets);
 		total_n_recs--;
 
 		if (total_data + page_dir_calc_reserved_space(total_n_recs)
@@ -2330,13 +2327,13 @@ btr_page_insert_fits(
 			/* Ok, there will be enough available space on the
 			half page where the tuple is inserted */
 
-			return(TRUE);
+			return(true);
 		}
 
 		rec = page_rec_get_next_const(rec);
 	}
 
-	return(FALSE);
+	return(false);
 }
 
 /*******************************************************//**
@@ -2358,6 +2355,8 @@ btr_insert_on_non_leaf_level_func(
 	btr_cur_t	cursor;
 	dberr_t		err;
 	rec_t*		rec;
+	ulint*		offsets	= NULL;
+	mem_heap_t*	heap = NULL;
 
 	ut_ad(level > 0);
 
@@ -2369,15 +2368,17 @@ btr_insert_on_non_leaf_level_func(
 					 | BTR_NO_LOCKING_FLAG
 					 | BTR_KEEP_SYS_FLAG
 					 | BTR_NO_UNDO_LOG_FLAG,
-					 &cursor, tuple, &rec,
+					 &cursor, &offsets, &heap,
+					 tuple, &rec,
 					 &dummy_big_rec, 0, NULL, mtr);
 	ut_a(err == DB_SUCCESS);
+	mem_heap_free(heap);
 }
 
 /**************************************************************//**
 Attaches the halves of an index page on the appropriate level in an
 index tree. */
-static
+static __attribute__((nonnull))
 void
 btr_attach_half_pages(
 /*==================*/
@@ -2513,13 +2514,13 @@ btr_attach_half_pages(
 /*************************************************************//**
 Determine if a tuple is smaller than any record on the page.
 @return TRUE if smaller */
-static
-ibool
+static __attribute__((nonnull, warn_unused_result))
+bool
 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**		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 */
@@ -2534,11 +2535,11 @@ btr_page_tuple_smaller(
 	page_cur_move_to_next(&pcur);
 	first_rec = page_cur_get_rec(&pcur);
 
-	offsets = rec_get_offsets(
-		first_rec, cursor->index, offsets,
+	*offsets = rec_get_offsets(
+		first_rec, cursor->index, *offsets,
 		n_uniq, heap);
 
-	return(cmp_dtuple_rec(tuple, first_rec, offsets) < 0);
+	return(cmp_dtuple_rec(tuple, first_rec, *offsets) < 0);
 }
 
 /*************************************************************//**
@@ -2558,6 +2559,8 @@ btr_page_split_and_insert(
 	btr_cur_t*	cursor,	/*!< in: cursor at which to insert; when the
 				function returns, the cursor is positioned
 				on the predecessor of the inserted record */
+	ulint**		offsets,/*!< out: offsets on inserted record */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr)	/*!< in: mtr */
@@ -2583,15 +2586,15 @@ btr_page_split_and_insert(
 	ibool		insert_left;
 	ulint		n_iterations = 0;
 	rec_t*		rec;
-	mem_heap_t*	heap;
 	ulint		n_uniq;
-	ulint*		offsets;
 
-	heap = mem_heap_create(1024);
+	if (!*heap) {
+		*heap = mem_heap_create(1024);
+	}
 	n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
 func_start:
-	mem_heap_empty(heap);
-	offsets = NULL;
+	mem_heap_empty(*heap);
+	*offsets = NULL;
 
 	ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index),
 				MTR_MEMO_X_LOCK));
@@ -2620,7 +2623,7 @@ func_start:
 
 		if (split_rec == NULL) {
 			insert_left = btr_page_tuple_smaller(
-				cursor, tuple, offsets, n_uniq, &heap);
+				cursor, tuple, offsets, n_uniq, heap);
 		}
 	} else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
 		direction = FSP_UP;
@@ -2642,7 +2645,7 @@ func_start:
 		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)) {
+						  offsets, n_uniq, heap)) {
 			split_rec = page_rec_get_next(
 				page_get_infimum_rec(page));
 		} else {
@@ -2665,10 +2668,10 @@ func_start:
 	if (split_rec) {
 		first_rec = move_limit = split_rec;
 
-		offsets = rec_get_offsets(split_rec, cursor->index, offsets,
-					  n_uniq, &heap);
+		*offsets = rec_get_offsets(split_rec, cursor->index, *offsets,
+					   n_uniq, heap);
 
-		insert_left = cmp_dtuple_rec(tuple, split_rec, offsets) < 0;
+		insert_left = cmp_dtuple_rec(tuple, split_rec, *offsets) < 0;
 
 		if (!insert_left && new_page_zip && n_iterations > 0) {
 			/* If a compressed page has already been split,
@@ -2715,7 +2718,7 @@ insert_empty:
 
 		insert_will_fit = !new_page_zip
 			&& btr_page_insert_fits(cursor, NULL,
-						NULL, tuple, n_ext, heap);
+						offsets, tuple, n_ext, heap);
 	}
 
 	if (insert_will_fit && page_is_leaf(page)) {
@@ -2835,8 +2838,8 @@ insert_empty:
 	page_cur_search(insert_block, cursor->index, tuple,
 			PAGE_CUR_LE, page_cursor);
 
-	rec = page_cur_tuple_insert(page_cursor, tuple,
-				    cursor->index, n_ext, mtr);
+	rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
+				    offsets, heap, n_ext, mtr);
 
 #ifdef UNIV_ZIP_DEBUG
 	{
@@ -2866,7 +2869,7 @@ insert_empty:
 	page_cur_search(insert_block, cursor->index, tuple,
 			PAGE_CUR_LE, page_cursor);
 	rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
-				    n_ext, mtr);
+				    offsets, heap, n_ext, mtr);
 
 	if (rec == NULL) {
 		/* The insert did not fit on the page: loop back to the
@@ -2907,7 +2910,7 @@ func_exit:
 	ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index));
 	ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index));
 
-	mem_heap_free(heap);
+	ut_ad(!rec || rec_offs_validate(rec, cursor->index, *offsets));
 	return(rec);
 }
 

=== modified file 'storage/innobase/btr/btr0cur.cc'
--- a/storage/innobase/btr/btr0cur.cc	revid:marko.makela@stripped82845-kp9aopbl2gjq7ana
+++ b/storage/innobase/btr/btr0cur.cc	revid:marko.makela@strippedba8sy6ic
@@ -1054,7 +1054,7 @@ be freed by reorganizing. Differs from b
 no heuristics is applied to whether it pays to use CPU time for
 reorganizing the page or not.
 @return	pointer to inserted record if succeed, else NULL */
-static
+static __attribute__((nonnull, warn_unused_result))
 rec_t*
 btr_cur_insert_if_possible(
 /*=======================*/
@@ -1062,6 +1062,8 @@ btr_cur_insert_if_possible(
 				cursor stays valid */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert; the size info need not
 				have been stored to tuple */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr)	/*!< in: mtr */
 {
@@ -1077,8 +1079,8 @@ btr_cur_insert_if_possible(
 	page_cursor = btr_cur_get_page_cur(cursor);
 
 	/* Now, try the insert */
-	rec = page_cur_tuple_insert(page_cursor, tuple,
-				    cursor->index, n_ext, mtr);
+	rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
+				    offsets, heap, n_ext, mtr);
 
 	if (UNIV_UNLIKELY(!rec)) {
 		/* If record did not fit, reorganize */
@@ -1088,11 +1090,13 @@ btr_cur_insert_if_possible(
 			page_cur_search(block, cursor->index, tuple,
 					PAGE_CUR_LE, page_cursor);
 
-			rec = page_cur_tuple_insert(page_cursor, tuple,
-						    cursor->index, n_ext, mtr);
+			rec = page_cur_tuple_insert(
+				page_cursor, tuple, cursor->index,
+				offsets, heap, n_ext, mtr);
 		}
 	}
 
+	ut_ad(!rec || rec_offs_validate(rec, cursor->index, *offsets));
 	return(rec);
 }
 
@@ -1191,6 +1195,8 @@ btr_cur_optimistic_insert(
 				specified */
 	btr_cur_t*	cursor,	/*!< in: cursor on page after which to insert;
 				cursor stays valid */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	dtuple_t*	entry,	/*!< in/out: entry to insert */
 	rec_t**		rec,	/*!< out: pointer to inserted record if
 				succeed */
@@ -1346,7 +1352,7 @@ fail_err:
 	{
 		const rec_t* page_cursor_rec = page_cur_get_rec(page_cursor);
 		*rec = page_cur_tuple_insert(page_cursor, entry, index,
-					     n_ext, mtr);
+					     offsets, heap, n_ext, mtr);
 		reorg = page_cursor_rec != page_cur_get_rec(page_cursor);
 
 		if (UNIV_UNLIKELY(reorg)) {
@@ -1371,7 +1377,7 @@ fail_err:
 		page_cur_search(block, index, entry, PAGE_CUR_LE, page_cursor);
 
 		*rec = page_cur_tuple_insert(page_cursor, entry, index,
-					     n_ext, mtr);
+					     offsets, heap, n_ext, mtr);
 
 		if (UNIV_UNLIKELY(!*rec)) {
 			if (zip_size != 0) {
@@ -1457,6 +1463,8 @@ btr_cur_pessimistic_insert(
 				insertion will certainly succeed */
 	btr_cur_t*	cursor,	/*!< in: cursor after which to insert;
 				cursor stays valid */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	dtuple_t*	entry,	/*!< in/out: entry to insert */
 	rec_t**		rec,	/*!< out: pointer to inserted record if
 				succeed */
@@ -1470,7 +1478,6 @@ btr_cur_pessimistic_insert(
 	dict_index_t*	index		= cursor->index;
 	ulint		zip_size	= dict_table_zip_size(index->table);
 	big_rec_t*	big_rec_vec	= NULL;
-	mem_heap_t*	heap		= NULL;
 	dberr_t		err;
 	ibool		dummy_inh;
 	ibool		success;
@@ -1493,8 +1500,9 @@ btr_cur_pessimistic_insert(
 
 	cursor->flag = BTR_CUR_BINARY;
 
-	err = btr_cur_optimistic_insert(flags, cursor, entry, rec,
-					big_rec, n_ext, thr, mtr);
+	err = btr_cur_optimistic_insert(
+		flags, cursor, offsets, heap, entry, rec,
+		big_rec, n_ext, thr, mtr);
 	if (err != DB_FAIL) {
 
 		return(err);
@@ -1556,14 +1564,10 @@ btr_cur_pessimistic_insert(
 
 		/* The page is the root page */
 		*rec = btr_root_raise_and_insert(
-			flags, cursor, entry, n_ext, mtr);
+			flags, cursor, offsets, heap, entry, n_ext, mtr);
 	} else {
 		*rec = btr_page_split_and_insert(
-			flags, cursor, entry, n_ext, mtr);
-	}
-
-	if (UNIV_LIKELY_NULL(heap)) {
-		mem_heap_free(heap);
+			flags, cursor, offsets, heap, entry, n_ext, mtr);
 	}
 
 	ut_ad(page_rec_get_next(btr_cur_get_rec(cursor)) == *rec);
@@ -2148,7 +2152,8 @@ any_extern:
 	}
 
 	/* There are no externally stored columns in new_entry */
-	rec = btr_cur_insert_if_possible(cursor, new_entry, 0/*n_ext*/, mtr);
+	rec = btr_cur_insert_if_possible(
+		cursor, new_entry, offsets, heap, 0/*n_ext*/, mtr);
 	ut_a(rec); /* <- We calculated above the insert would fit */
 
 	if (page_zip && !dict_index_is_clust(index)
@@ -2427,7 +2432,8 @@ make_external:
 
 	page_cur_move_to_prev(page_cursor);
 
-	rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr);
+	rec = btr_cur_insert_if_possible(cursor, new_entry,
+					 offsets, heap, n_ext, mtr);
 
 	if (rec) {
 		page_cursor->rec = rec;
@@ -2435,9 +2441,6 @@ make_external:
 		lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor),
 						   rec, block);
 
-		*offsets = rec_get_offsets(rec, index, *offsets,
-					   ULINT_UNDEFINED, heap);
-
 		if (!rec_get_deleted_flag(rec, rec_offs_comp(*offsets))) {
 			/* The new inserted record owns its possible externally
 			stored fields */
@@ -2493,11 +2496,13 @@ make_external:
 	err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG
 					 | BTR_NO_LOCKING_FLAG
 					 | BTR_KEEP_SYS_FLAG,
-					 cursor, new_entry, &rec,
+					 cursor, offsets, heap,
+					 new_entry, &rec,
 					 &dummy_big_rec, n_ext, NULL, mtr);
 	ut_a(rec);
 	ut_a(err == DB_SUCCESS);
 	ut_a(dummy_big_rec == NULL);
+	ut_ad(rec_offs_validate(rec, cursor->index, *offsets));
 	page_cursor->rec = rec;
 
 	if (dict_index_is_sec_or_ibuf(index)) {
@@ -2524,8 +2529,6 @@ make_external:
 #endif /* UNIV_ZIP_DEBUG */
 		page_zip = buf_block_get_page_zip(rec_block);
 
-		*offsets = rec_get_offsets(rec, index, *offsets,
-					   ULINT_UNDEFINED, heap);
 		btr_cur_unmark_extern_fields(page_zip,
 					     rec, index, *offsets, mtr);
 	}
@@ -3167,8 +3170,8 @@ btr_cur_pessimistic_delete(
 				index, next_rec, buf_block_get_page_no(block),
 				heap, level);
 
-			btr_insert_on_non_leaf_level(flags, index,
-						     level + 1, node_ptr, mtr);
+			btr_insert_on_non_leaf_level(
+				flags, index, level + 1, node_ptr, mtr);
 		}
 	}
 

=== modified file 'storage/innobase/ibuf/ibuf0ibuf.cc'
--- a/storage/innobase/ibuf/ibuf0ibuf.cc	revid:marko.makela@oracle.com-20120522082845-kp9aopbl2gjq7ana
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc	revid:marko.makela@stripped523084804-es3dmpmzba8sy6ic
@@ -3239,6 +3239,7 @@ ibuf_insert_low(
 	btr_cur_t*	cursor;
 	dtuple_t*	ibuf_entry;
 	mem_heap_t*	heap;
+	ulint*		offsets		= NULL;
 	ulint		buffered;
 	lint		min_n_recs;
 	rec_t*		ins_rec;
@@ -3286,7 +3287,7 @@ ibuf_insert_low(
 		return(DB_STRONG_FAIL);
 	}
 
-	heap = mem_heap_create(512);
+	heap = mem_heap_create(1024);
 
 	/* Build the entry which contains the space id and the page number
 	as the first fields and the type information for other fields, and
@@ -3456,9 +3457,11 @@ fail_exit:
 	cursor = btr_pcur_get_btr_cur(&pcur);
 
 	if (mode == BTR_MODIFY_PREV) {
-		err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
-						ibuf_entry, &ins_rec,
-						&dummy_big_rec, 0, thr, &mtr);
+		err = btr_cur_optimistic_insert(
+			BTR_NO_LOCKING_FLAG,
+			cursor, &offsets, &heap,
+			ibuf_entry, &ins_rec,
+			&dummy_big_rec, 0, thr, &mtr);
 		block = btr_cur_get_block(cursor);
 		ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
 
@@ -3485,7 +3488,7 @@ fail_exit:
 
 		err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
 						 | BTR_NO_UNDO_LOG_FLAG,
-						 cursor,
+						 cursor, &offsets, &heap,
 						 ibuf_entry, &ins_rec,
 						 &dummy_big_rec, 0, thr, &mtr);
 		mutex_exit(&ibuf_pessimistic_insert_mutex);
@@ -3684,7 +3687,7 @@ skip_watch:
 /********************************************************************//**
 During merge, inserts to an index page a secondary index entry extracted
 from the insert buffer. */
-static
+static __attribute__((nonnull))
 void
 ibuf_insert_to_index_page_low(
 /*==========================*/
@@ -3692,6 +3695,8 @@ ibuf_insert_to_index_page_low(
 	buf_block_t*	block,	/*!< in/out: index page where the buffered
 				entry should be placed */
 	dict_index_t*	index,	/*!< in: record descriptor */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t*	heap,	/*!< in/out: memory heap */
 	mtr_t*		mtr,	/*!< in/out: mtr */
 	page_cur_t*	page_cur)/*!< in/out: cursor positioned on the record
 				after which to insert the buffered entry */
@@ -3703,8 +3708,8 @@ ibuf_insert_to_index_page_low(
 	const page_t*	bitmap_page;
 	ulint		old_bits;
 
-	if (UNIV_LIKELY
-	    (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
+	if (page_cur_tuple_insert(
+		    page_cur, entry, index, offsets, &heap, 0, mtr) != NULL) {
 		return;
 	}
 
@@ -3715,8 +3720,8 @@ ibuf_insert_to_index_page_low(
 
 	/* This time the record must fit */
 
-	if (UNIV_LIKELY
-	    (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
+	if (page_cur_tuple_insert(page_cur, entry, index,
+				  offsets, &heap, 0, mtr) != NULL) {
 		return;
 	}
 
@@ -3770,6 +3775,8 @@ ibuf_insert_to_index_page(
 	ulint		low_match;
 	page_t*		page		= buf_block_get_frame(block);
 	rec_t*		rec;
+	ulint*		offsets;
+	mem_heap_t*	heap;
 
 	ut_ad(ibuf_inside(mtr));
 	ut_ad(dtuple_check_typed(entry));
@@ -3820,10 +3827,14 @@ dump:
 	low_match = page_cur_search(block, index, entry,
 				    PAGE_CUR_LE, &page_cur);
 
+	heap = mem_heap_create(
+		sizeof(upd_t)
+		+ REC_OFFS_HEADER_SIZE * sizeof(*offsets)
+		+ dtuple_get_n_fields(entry)
+		* (sizeof(upd_field_t) + sizeof *offsets));
+
 	if (UNIV_UNLIKELY(low_match == dtuple_get_n_fields(entry))) {
-		mem_heap_t*	heap;
 		upd_t*		update;
-		ulint*		offsets;
 		page_zip_des_t*	page_zip;
 
 		rec = page_cur_get_rec(&page_cur);
@@ -3832,12 +3843,6 @@ dump:
 		row_ins_sec_index_entry_by_modify(BTR_MODIFY_LEAF). */
 		ut_ad(rec_get_deleted_flag(rec, page_is_comp(page)));
 
-		heap = mem_heap_create(
-			sizeof(upd_t)
-			+ REC_OFFS_HEADER_SIZE * sizeof(*offsets)
-			+ dtuple_get_n_fields(entry)
-			* (sizeof(upd_field_t) + sizeof *offsets));
-
 		offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED,
 					  &heap);
 		update = row_upd_build_sec_rec_difference_binary(
@@ -3851,9 +3856,7 @@ dump:
 			Bug #56680 was fixed. */
 			btr_cur_set_deleted_flag_for_ibuf(
 				rec, page_zip, FALSE, mtr);
-updated_in_place:
-			mem_heap_free(heap);
-			return;
+			goto updated_in_place;
 		}
 
 		/* Copy the info bits. Clear the delete-mark. */
@@ -3897,15 +3900,20 @@ updated_in_place:
 		lock_rec_store_on_page_infimum(block, rec);
 		page_cur_delete_rec(&page_cur, index, offsets, mtr);
 		page_cur_move_to_prev(&page_cur);
-		mem_heap_free(heap);
 
-		ibuf_insert_to_index_page_low(entry, block, index, mtr,
+		ibuf_insert_to_index_page_low(entry, block, index,
+					      &offsets, heap, mtr,
 					      &page_cur);
 		lock_rec_restore_from_page_infimum(block, rec, block);
 	} else {
-		ibuf_insert_to_index_page_low(entry, block, index, mtr,
+		offsets = NULL;
+		ibuf_insert_to_index_page_low(entry, block, index,
+					      &offsets, heap, mtr,
 					      &page_cur);
 	}
+
+updated_in_place:
+	mem_heap_free(heap);
 }
 
 /****************************************************************//**

=== modified file 'storage/innobase/include/btr0btr.h'
--- a/storage/innobase/include/btr0btr.h	revid:marko.makela@oracle.com-20120522082845-kp9aopbl2gjq7ana
+++ b/storage/innobase/include/btr0btr.h	revid:marko.makela@stripped523084804-es3dmpmzba8sy6ic
@@ -217,7 +217,8 @@ page_t*
 btr_root_get(
 /*=========*/
 	dict_index_t*	index,	/*!< in: index tree */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 /**************************************************************//**
 Gets the height of the B-tree (the level of the root, when the leaf
 level is assumed to be 0). The caller must hold an S or X latch on
@@ -290,7 +291,8 @@ UNIV_INLINE
 index_id_t
 btr_page_get_index_id(
 /*==================*/
-	const page_t*	page);	/*!< in: index page */
+	const page_t*	page)	/*!< in: index page */
+	__attribute__((nonnull, pure, warn_unused_result));
 #ifndef UNIV_HOTBACKUP
 /********************************************************//**
 Gets the node level field in an index page.
@@ -299,16 +301,9 @@ UNIV_INLINE
 ulint
 btr_page_get_level_low(
 /*===================*/
-	const page_t*	page);	/*!< in: index page */
-/********************************************************//**
-Gets the node level field in an index page.
-@return	level, leaf level == 0 */
-UNIV_INLINE
-ulint
-btr_page_get_level(
-/*===============*/
-	const page_t*	page,	/*!< in: index page */
-	mtr_t*		mtr);	/*!< in: mini-transaction handle */
+	const page_t*	page)	/*!< in: index page */
+	__attribute__((nonnull, pure, warn_unused_result));
+#define btr_page_get_level(page, mtr) btr_page_get_level_low(page)
 /********************************************************//**
 Gets the next index page number.
 @return	next page number */
@@ -317,7 +312,8 @@ ulint
 btr_page_get_next(
 /*==============*/
 	const page_t*	page,	/*!< in: index page */
-	mtr_t*		mtr);	/*!< in: mini-transaction handle */
+	mtr_t*		mtr)	/*!< in: mini-transaction handle */
+	__attribute__((nonnull, warn_unused_result));
 /********************************************************//**
 Gets the previous index page number.
 @return	prev page number */
@@ -326,7 +322,8 @@ ulint
 btr_page_get_prev(
 /*==============*/
 	const page_t*	page,	/*!< in: index page */
-	mtr_t*		mtr);	/*!< in: mini-transaction handle */
+	mtr_t*		mtr)	/*!< in: mini-transaction handle */
+	__attribute__((nonnull, warn_unused_result));
 /*************************************************************//**
 Gets pointer to the previous user record in the tree. It is assumed
 that the caller has appropriate latches on the page and its neighbor.
@@ -336,8 +333,9 @@ rec_t*
 btr_get_prev_user_rec(
 /*==================*/
 	rec_t*	rec,	/*!< in: record on leaf level */
-	mtr_t*	mtr);	/*!< in: mtr holding a latch on the page, and if
+	mtr_t*	mtr)	/*!< in: mtr holding a latch on the page, and if
 			needed, also to the previous page */
+	__attribute__((nonnull, warn_unused_result));
 /*************************************************************//**
 Gets pointer to the next user record in the tree. It is assumed
 that the caller has appropriate latches on the page and its neighbor.
@@ -347,8 +345,9 @@ rec_t*
 btr_get_next_user_rec(
 /*==================*/
 	rec_t*	rec,	/*!< in: record on leaf level */
-	mtr_t*	mtr);	/*!< in: mtr holding a latch on the page, and if
+	mtr_t*	mtr)	/*!< in: mtr holding a latch on the page, and if
 			needed, also to the next page */
+	__attribute__((nonnull, warn_unused_result));
 /**************************************************************//**
 Releases the latch on a leaf page and bufferunfixes it. */
 UNIV_INLINE
@@ -358,7 +357,8 @@ btr_leaf_page_release(
 	buf_block_t*	block,		/*!< in: buffer block */
 	ulint		latch_mode,	/*!< in: BTR_SEARCH_LEAF or
 					BTR_MODIFY_LEAF */
-	mtr_t*		mtr);		/*!< in: mtr */
+	mtr_t*		mtr)		/*!< in: mtr */
+	__attribute__((nonnull));
 /**************************************************************//**
 Gets the child node file address in a node pointer.
 NOTE: the offsets array must contain all offsets for the record since
@@ -371,7 +371,8 @@ ulint
 btr_node_ptr_get_child_page_no(
 /*===========================*/
 	const rec_t*	rec,	/*!< in: node pointer record */
-	const ulint*	offsets);/*!< in: array returned by rec_get_offsets() */
+	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
+	__attribute__((nonnull, pure, warn_unused_result));
 /************************************************************//**
 Creates the root node for a new index tree.
 @return	page number of the created root, FIL_NULL if did not succeed */
@@ -385,7 +386,8 @@ btr_create(
 				or 0 for uncompressed pages */
 	index_id_t	index_id,/*!< in: index id */
 	dict_index_t*	index,	/*!< in: index */
-	mtr_t*		mtr);	/*!< in: mini-transaction handle */
+	mtr_t*		mtr)	/*!< in: mini-transaction handle */
+	__attribute__((nonnull));
 /************************************************************//**
 Frees a B-tree except the root page, which MUST be freed after this
 by calling btr_free_root. */
@@ -407,7 +409,8 @@ btr_free_root(
 	ulint	zip_size,	/*!< in: compressed page size in bytes
 				or 0 for uncompressed pages */
 	ulint	root_page_no,	/*!< in: root page number */
-	mtr_t*	mtr);		/*!< in/out: mini-transaction */
+	mtr_t*	mtr)		/*!< in/out: mini-transaction */
+	__attribute__((nonnull));
 /*************************************************************//**
 Makes tree one level higher by splitting the root, and inserts
 the tuple. It is assumed that mtr contains an x-latch on the tree.
@@ -424,9 +427,12 @@ btr_root_raise_and_insert(
 				on the root page; when the function returns,
 				the cursor is positioned on the predecessor
 				of the inserted record */
+	ulint**		offsets,/*!< out: offsets on inserted record */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull, warn_unused_result));
 /*************************************************************//**
 Reorganizes an index page.
 IMPORTANT: if btr_page_reorganize() is invoked on a compressed leaf
@@ -440,7 +446,8 @@ btr_page_reorganize(
 /*================*/
 	buf_block_t*	block,	/*!< in: page to be reorganized */
 	dict_index_t*	index,	/*!< in: record descriptor */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 /*************************************************************//**
 Decides if the page should be split at the convergence point of
 inserts converging to left.
@@ -450,9 +457,10 @@ ibool
 btr_page_get_split_rec_to_left(
 /*===========================*/
 	btr_cur_t*	cursor,	/*!< in: cursor at which to insert */
-	rec_t**		split_rec);/*!< out: if split recommended,
+	rec_t**		split_rec)/*!< out: if split recommended,
 				the first record on upper half page,
 				or NULL if tuple should be first */
+	__attribute__((nonnull, warn_unused_result));
 /*************************************************************//**
 Decides if the page should be split at the convergence point of
 inserts converging to right.
@@ -462,9 +470,10 @@ ibool
 btr_page_get_split_rec_to_right(
 /*============================*/
 	btr_cur_t*	cursor,	/*!< in: cursor at which to insert */
-	rec_t**		split_rec);/*!< out: if split recommended,
+	rec_t**		split_rec)/*!< out: if split recommended,
 				the first record on upper half page,
 				or NULL if tuple should be first */
+	__attribute__((nonnull, warn_unused_result));
 /*************************************************************//**
 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
@@ -482,9 +491,12 @@ btr_page_split_and_insert(
 	btr_cur_t*	cursor,	/*!< in: cursor at which to insert; when the
 				function returns, the cursor is positioned
 				on the predecessor of the inserted record */
+	ulint**		offsets,/*!< out: offsets on inserted record */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull, warn_unused_result));
 /*******************************************************//**
 Inserts a data tuple to a tree on a non-leaf level. It is assumed
 that mtr holds an x-latch on the tree. */
@@ -498,7 +510,8 @@ btr_insert_on_non_leaf_level_func(
 	dtuple_t*	tuple,	/*!< in: the record to be inserted */
 	const char*	file,	/*!< in: file name */
 	ulint		line,	/*!< in: line where called */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 # define btr_insert_on_non_leaf_level(f,i,l,t,m)			\
 	btr_insert_on_non_leaf_level_func(f,i,l,t,__FILE__,__LINE__,m)
 #endif /* !UNIV_HOTBACKUP */
@@ -509,7 +522,8 @@ void
 btr_set_min_rec_mark(
 /*=================*/
 	rec_t*	rec,	/*!< in/out: record */
-	mtr_t*	mtr);	/*!< in: mtr */
+	mtr_t*	mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 #ifndef UNIV_HOTBACKUP
 /*************************************************************//**
 Deletes on the upper level the node pointer to a page. */
@@ -519,7 +533,8 @@ btr_node_ptr_delete(
 /*================*/
 	dict_index_t*	index,	/*!< in: index tree */
 	buf_block_t*	block,	/*!< in: page whose node pointer is deleted */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 #ifdef UNIV_DEBUG
 /************************************************************//**
 Checks that the node pointer to a page is appropriate.
@@ -530,7 +545,8 @@ btr_check_node_ptr(
 /*===============*/
 	dict_index_t*	index,	/*!< in: index tree */
 	buf_block_t*	block,	/*!< in: index page */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull, warn_unused_result));
 #endif /* UNIV_DEBUG */
 /*************************************************************//**
 Tries to merge the page first to the left immediate brother if such a
@@ -564,7 +580,8 @@ btr_discard_page(
 /*=============*/
 	btr_cur_t*	cursor,	/*!< in: cursor on the page to discard: not on
 				the root page */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 #endif /* !UNIV_HOTBACKUP */
 /****************************************************************//**
 Parses the redo log record for setting an index record as the predefined
@@ -578,7 +595,8 @@ btr_parse_set_min_rec_mark(
 	byte*	end_ptr,/*!< in: buffer end */
 	ulint	comp,	/*!< in: nonzero=compact page format */
 	page_t*	page,	/*!< in: page or NULL */
-	mtr_t*	mtr);	/*!< in: mtr or NULL */
+	mtr_t*	mtr)	/*!< in: mtr or NULL */
+	__attribute__((nonnull(1,2), warn_unused_result));
 /***********************************************************//**
 Parses a redo log record of reorganizing a page.
 @return	end of log record or NULL */
@@ -590,7 +608,8 @@ btr_parse_page_reorganize(
 	byte*		end_ptr,/*!< in: buffer end */
 	dict_index_t*	index,	/*!< in: record descriptor */
 	buf_block_t*	block,	/*!< in: page to be reorganized, or NULL */
-	mtr_t*		mtr);	/*!< in: mtr or NULL */
+	mtr_t*		mtr)	/*!< in: mtr or NULL */
+	__attribute__((nonnull(1,2,3), warn_unused_result));
 #ifndef UNIV_HOTBACKUP
 /**************************************************************//**
 Gets the number of pages in a B-tree.
@@ -636,7 +655,8 @@ btr_page_free(
 /*==========*/
 	dict_index_t*	index,	/*!< in: index tree */
 	buf_block_t*	block,	/*!< in: block to be freed, x-latched */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 /**************************************************************//**
 Frees a file page used in an index tree. Can be used also to BLOB
 external storage pages, because the page level 0 can be given as an
@@ -648,7 +668,8 @@ btr_page_free_low(
 	dict_index_t*	index,	/*!< in: index tree */
 	buf_block_t*	block,	/*!< in: block to be freed, x-latched */
 	ulint		level,	/*!< in: page level */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull));
 #ifdef UNIV_BTR_PRINT
 /*************************************************************//**
 Prints size info of a B-tree. */
@@ -656,7 +677,8 @@ UNIV_INTERN
 void
 btr_print_size(
 /*===========*/
-	dict_index_t*	index);	/*!< in: index tree */
+	dict_index_t*	index)	/*!< in: index tree */
+	__attribute__((nonnull));
 /**************************************************************//**
 Prints directories and other info of all nodes in the index. */
 UNIV_INTERN
@@ -664,8 +686,9 @@ void
 btr_print_index(
 /*============*/
 	dict_index_t*	index,	/*!< in: index */
-	ulint		width);	/*!< in: print this many entries from start
+	ulint		width)	/*!< in: print this many entries from start
 				and end */
+	__attribute__((nonnull));
 #endif /* UNIV_BTR_PRINT */
 /************************************************************//**
 Checks the size and number of fields in a record based on the definition of
@@ -677,9 +700,10 @@ btr_index_rec_validate(
 /*===================*/
 	const rec_t*		rec,		/*!< in: index record */
 	const dict_index_t*	index,		/*!< in: index */
-	ibool			dump_on_error);	/*!< in: TRUE if the function
+	ibool			dump_on_error)	/*!< in: TRUE if the function
 						should print hex dump of record
 						and page on error */
+	__attribute__((nonnull, warn_unused_result));
 /**************************************************************//**
 Checks the consistency of an index tree.
 @return	TRUE if ok */
@@ -688,7 +712,8 @@ ibool
 btr_validate_index(
 /*===============*/
 	dict_index_t*	index,	/*!< in: index */
-	trx_t*		trx);	/*!< in: transaction or NULL */
+	trx_t*		trx)	/*!< in: transaction or NULL */
+	__attribute__((nonnull(1), warn_unused_result));
 
 #define BTR_N_LEAF_PAGES	1
 #define BTR_TOTAL_SIZE		2

=== modified file 'storage/innobase/include/btr0btr.ic'
--- a/storage/innobase/include/btr0btr.ic	revid:marko.makela@stripped7ana
+++ b/storage/innobase/include/btr0btr.ic	revid:marko.makela@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2012, 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
@@ -126,22 +126,6 @@ btr_page_get_level_low(
 }
 
 /********************************************************//**
-Gets the node level field in an index page.
-@return	level, leaf level == 0 */
-UNIV_INLINE
-ulint
-btr_page_get_level(
-/*===============*/
-	const page_t*	page,	/*!< in: index page */
-	mtr_t*		mtr __attribute__((unused)))
-				/*!< in: mini-transaction handle */
-{
-	ut_ad(page && mtr);
-
-	return(btr_page_get_level_low(page));
-}
-
-/********************************************************//**
 Sets the node level field in an index page. */
 UNIV_INLINE
 void
@@ -278,6 +262,7 @@ btr_node_ptr_get_child_page_no(
 			" in a node ptr record at offset %lu\n",
 			(ulong) page_offset(rec));
 		buf_page_print(page_align(rec), 0, 0);
+		ut_ad(0);
 	}
 
 	return(page_no);

=== modified file 'storage/innobase/include/btr0cur.h'
--- a/storage/innobase/include/btr0cur.h	revid:marko.makela@stripped
+++ b/storage/innobase/include/btr0cur.h	revid:marko.makela@oracle.com-20120523084804-es3dmpmzba8sy6ic
@@ -212,6 +212,8 @@ btr_cur_optimistic_insert(
 				specified */
 	btr_cur_t*	cursor,	/*!< in: cursor on page after which to insert;
 				cursor stays valid */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	dtuple_t*	entry,	/*!< in/out: entry to insert */
 	rec_t**		rec,	/*!< out: pointer to inserted record if
 				succeed */
@@ -225,7 +227,7 @@ btr_cur_optimistic_insert(
 				index in a compressed tablespace, the
 				mtr must be committed before latching
 				any further pages */
-	__attribute__((nonnull(2,3,4,5,8), warn_unused_result));
+	__attribute__((nonnull(2,3,4,5,6,7,10), warn_unused_result));
 /*************************************************************//**
 Performs an insert on a page of an index tree. It is assumed that mtr
 holds an x-latch on the tree and on the cursor page. If the insert is
@@ -244,6 +246,8 @@ btr_cur_pessimistic_insert(
 				insertion will certainly succeed */
 	btr_cur_t*	cursor,	/*!< in: cursor after which to insert;
 				cursor stays valid */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	dtuple_t*	entry,	/*!< in/out: entry to insert */
 	rec_t**		rec,	/*!< out: pointer to inserted record if
 				succeed */
@@ -253,7 +257,7 @@ btr_cur_pessimistic_insert(
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	que_thr_t*	thr,	/*!< in: query thread or NULL */
 	mtr_t*		mtr)	/*!< in: mtr */
-	__attribute__((nonnull(2,3,4,5,8), warn_unused_result));
+	__attribute__((nonnull(2,3,4,5,6,7,10), warn_unused_result));
 /*************************************************************//**
 See if there is enough place in the page modification log to log
 an update-in-place.

=== modified file 'storage/innobase/include/page0cur.h'
--- a/storage/innobase/include/page0cur.h	revid:marko.makela@oracle.com-20120522082845-kp9aopbl2gjq7ana
+++ b/storage/innobase/include/page0cur.h	revid:marko.makela@stripped20523084804-es3dmpmzba8sy6ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2009, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2012, 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
@@ -170,8 +170,11 @@ page_cur_tuple_insert(
 	page_cur_t*	cursor,	/*!< in/out: a page cursor */
 	const dtuple_t*	tuple,	/*!< in: pointer to a data tuple */
 	dict_index_t*	index,	/*!< in: record descriptor */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
-	mtr_t*		mtr);	/*!< in: mini-transaction handle, or NULL */
+	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
+	__attribute__((nonnull(1,2,3,4,5), warn_unused_result));
 #endif /* !UNIV_HOTBACKUP */
 /***********************************************************//**
 Inserts a record next to page cursor. Returns pointer to inserted record if

=== modified file 'storage/innobase/include/page0cur.ic'
--- a/storage/innobase/include/page0cur.ic	revid:marko.makela@oracle.com-20120522082845-kp9aopbl2gjq7ana
+++ b/storage/innobase/include/page0cur.ic	revid:marko.makela@stripped120523084804-es3dmpmzba8sy6ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2012, 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
@@ -245,33 +245,36 @@ page_cur_tuple_insert(
 	page_cur_t*	cursor,	/*!< in/out: a page cursor */
 	const dtuple_t*	tuple,	/*!< in: pointer to a data tuple */
 	dict_index_t*	index,	/*!< in: record descriptor */
+	ulint**		offsets,/*!< out: offsets on *rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr)	/*!< in: mini-transaction handle, or NULL */
 {
-	mem_heap_t*	heap;
-	ulint*		offsets;
 	ulint		size
 		= rec_get_converted_size(index, tuple, n_ext);
 	rec_t*		rec;
 
-	heap = mem_heap_create(size
-			       + (4 + REC_OFFS_HEADER_SIZE
-				  + dtuple_get_n_fields(tuple))
-			       * sizeof *offsets);
-	rec = rec_convert_dtuple_to_rec((byte*) mem_heap_alloc(heap, size),
+	if (!*heap) {
+		*heap = mem_heap_create(size
+					+ (4 + REC_OFFS_HEADER_SIZE
+					   + dtuple_get_n_fields(tuple))
+					* sizeof **offsets);
+	}
+
+	rec = rec_convert_dtuple_to_rec((byte*) mem_heap_alloc(*heap, size),
 					index, tuple, n_ext);
-	offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+	*offsets = rec_get_offsets(
+		rec, index, *offsets, ULINT_UNDEFINED, heap);
 
 	if (buf_block_get_page_zip(cursor->block)) {
 		rec = page_cur_insert_rec_zip(&cursor->rec, cursor->block,
-					      index, rec, offsets, mtr);
+					      index, rec, *offsets, mtr);
 	} else {
 		rec = page_cur_insert_rec_low(cursor->rec,
-					      index, rec, offsets, mtr);
+					      index, rec, *offsets, mtr);
 	}
 
-	ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, offsets));
-	mem_heap_free(heap);
+	ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, *offsets));
 	return(rec);
 }
 #endif /* !UNIV_HOTBACKUP */

=== modified file 'storage/innobase/row/row0ins.cc'
--- a/storage/innobase/row/row0ins.cc	revid:marko.makela@strippedp9aopbl2gjq7ana
+++ b/storage/innobase/row/row0ins.cc	revid:marko.makela@strippedc
@@ -234,16 +234,16 @@ row_ins_sec_index_entry_by_modify(
 				depending on whether mtr holds just a leaf
 				latch or also a tree latch */
 	btr_cur_t*	cursor,	/*!< in: B-tree cursor */
+	ulint**		offsets,/*!< in/out: offsets on cursor->page_cur.rec */
+	mem_heap_t*	heap,	/*!< in/out: memory heap */
 	const dtuple_t*	entry,	/*!< in: index entry to insert */
 	que_thr_t*	thr,	/*!< in: query thread */
 	mtr_t*		mtr)	/*!< in: mtr; must be committed before
 				latching any further pages */
 {
 	big_rec_t*	dummy_big_rec;
-	mem_heap_t*	heap;
 	upd_t*		update;
 	rec_t*		rec;
-	ulint*		offsets;
 	dberr_t		err;
 
 	rec = btr_cur_get_rec(cursor);
@@ -251,29 +251,23 @@ row_ins_sec_index_entry_by_modify(
 	ut_ad(!dict_index_is_clust(cursor->index));
 	ut_ad(rec_get_deleted_flag(rec,
 				   dict_table_is_comp(cursor->index->table)));
+	ut_ad(rec_offs_validate(rec, cursor->index, *offsets));
 
 	/* We know that in the alphabetical ordering, entry and rec are
 	identified. But in their binary form there may be differences if
 	there are char fields in them. Therefore we have to calculate the
 	difference. */
 
-	heap = mem_heap_create(
-		sizeof(upd_t)
-		+ REC_OFFS_HEADER_SIZE * sizeof(*offsets)
-		+ dtuple_get_n_fields(entry)
-		* (sizeof(upd_field_t) + sizeof *offsets));
-	offsets = rec_get_offsets(rec, cursor->index, NULL,
-				  ULINT_UNDEFINED, &heap);
 	update = row_upd_build_sec_rec_difference_binary(
-		rec, cursor->index, offsets, entry, heap);
+		rec, cursor->index, *offsets, entry, heap);
 	if (mode == BTR_MODIFY_LEAF) {
 		/* Try an optimistic updating of the record, keeping changes
 		within the page */
 
-		/* TODO: pass only offsets, no &offsets, &heap */
+		/* TODO: pass only *offsets */
 		err = btr_cur_optimistic_update(
 			BTR_KEEP_SYS_FLAG, cursor,
-			&offsets, &heap, update, 0, thr,
+			offsets, &heap, update, 0, thr,
 			thr_get_trx(thr)->id, mtr);
 		switch (err) {
 		case DB_OVERFLOW:
@@ -287,19 +281,15 @@ row_ins_sec_index_entry_by_modify(
 		ut_a(mode == BTR_MODIFY_TREE);
 		if (buf_LRU_buf_pool_running_out()) {
 
-			err = DB_LOCK_TABLE_FULL;
-
-			goto func_exit;
+			return(DB_LOCK_TABLE_FULL);
 		}
 
 		err = btr_cur_pessimistic_update(
 			BTR_KEEP_SYS_FLAG, cursor,
-			&offsets, &heap, &dummy_big_rec, update, 0, thr,
+			offsets, &heap, &dummy_big_rec, update, 0, thr,
 			thr_get_trx(thr)->id, mtr);
 		ut_ad(!dummy_big_rec);
 	}
-func_exit:
-	mem_heap_free(heap);
 
 	return(err);
 }
@@ -2273,7 +2263,8 @@ err_exit:
 		if (mode != BTR_MODIFY_TREE) {
 			ut_ad(mode == BTR_MODIFY_LEAF);
 			err = btr_cur_optimistic_insert(
-				0, &cursor, entry, &insert_rec, &big_rec,
+				0, &cursor, &offsets, &heap,
+				entry, &insert_rec, &big_rec,
 				n_ext, thr, &mtr);
 		} else {
 			if (buf_LRU_buf_pool_running_out()) {
@@ -2282,7 +2273,8 @@ err_exit:
 				goto err_exit;
 			}
 			err = btr_cur_pessimistic_insert(
-				0, &cursor, entry, &insert_rec, &big_rec,
+				0, &cursor, &offsets, &heap,
+				entry, &insert_rec, &big_rec,
 				n_ext, thr, &mtr);
 		}
 
@@ -2301,9 +2293,10 @@ err_exit:
 		}
 	}
 
-	if (UNIV_LIKELY_NULL(heap)) {
+	if (heap) {
 		mem_heap_free(heap);
 	}
+
 	return(err);
 }
 
@@ -2321,6 +2314,7 @@ row_ins_sec_index_entry_low(
 				depending on whether we wish optimistic or
 				pessimistic descent down the index tree */
 	dict_index_t*	index,	/*!< in: secondary index */
+	mem_heap_t*	heap,	/*!< in/out: memory heap */
 	dtuple_t*	entry,	/*!< in/out: index entry to insert */
 	que_thr_t*	thr)	/*!< in: query thread */
 {
@@ -2329,6 +2323,7 @@ row_ins_sec_index_entry_low(
 	dberr_t		err;
 	ulint		n_unique;
 	mtr_t		mtr;
+	ulint*		offsets	= NULL;
 
 	ut_ad(!dict_index_is_clust(index));
 	ut_ad(!dict_index_is_online_ddl(index));
@@ -2403,16 +2398,20 @@ row_ins_sec_index_entry_low(
 		/* There is already an index entry with a long enough common
 		prefix, we must convert the insert into a modify of an
 		existing record */
+		offsets = rec_get_offsets(
+			btr_cur_get_rec(&cursor), index, offsets,
+			ULINT_UNDEFINED, &heap);
 
 		err = row_ins_sec_index_entry_by_modify(
-			mode, &cursor, entry, thr, &mtr);
+			mode, &cursor, &offsets, heap, entry, thr, &mtr);
 	} else {
 		rec_t*		insert_rec;
 		big_rec_t*	big_rec;
 
 		if (mode == BTR_MODIFY_LEAF) {
 			err = btr_cur_optimistic_insert(
-				0, &cursor, entry, &insert_rec,
+				0, &cursor, &offsets, &heap,
+				entry, &insert_rec,
 				&big_rec, 0, thr, &mtr);
 		} else {
 			ut_ad(mode == BTR_MODIFY_TREE);
@@ -2421,7 +2420,8 @@ row_ins_sec_index_entry_low(
 				err = DB_LOCK_TABLE_FULL;
 			} else {
 				err = btr_cur_pessimistic_insert(
-					0, &cursor, entry, &insert_rec,
+					0, &cursor, &offsets, &heap,
+					entry, &insert_rec,
 					&big_rec, 0, thr, &mtr);
 			}
 		}
@@ -2536,7 +2536,8 @@ row_ins_sec_index_entry(
 	dtuple_t*	entry,	/*!< in/out: index entry to insert */
 	que_thr_t*	thr)	/*!< in: query thread */
 {
-	dberr_t	err;
+	dberr_t		err;
+	mem_heap_t*	heap;
 
 	if (UT_LIST_GET_FIRST(index->table->foreign_list)) {
 		err = row_ins_check_foreign_constraints(index->table, index,
@@ -2552,18 +2553,23 @@ row_ins_sec_index_entry(
 		return(DB_SUCCESS);
 	}
 
+	heap = mem_heap_create(1024);
+
 	/* Try first optimistic descent to the B-tree */
 
-	err = row_ins_sec_index_entry_low(BTR_MODIFY_LEAF, index, entry, thr);
-	if (err != DB_FAIL) {
+	err = row_ins_sec_index_entry_low(BTR_MODIFY_LEAF, index, heap,
+					  entry, thr);
+	if (err == DB_FAIL) {
+		mem_heap_empty(heap);
 
-		return(err);
-	}
+		/* Try then pessimistic descent to the B-tree */
 
-	/* Try then pessimistic descent to the B-tree */
+		err = row_ins_sec_index_entry_low(
+			BTR_MODIFY_TREE, index, heap, entry, thr);
+	}
 
-	return(row_ins_sec_index_entry_low(
-		       BTR_MODIFY_TREE, index, entry, thr));
+	mem_heap_free(heap);
+	return(err);
 }
 
 /***************************************************************//**

=== modified file 'storage/innobase/row/row0log.cc'
--- a/storage/innobase/row/row0log.cc	revid:marko.makela@stripped
+++ b/storage/innobase/row/row0log.cc	revid:marko.makela@strippedm-20120523084804-es3dmpmzba8sy6ic
@@ -105,32 +105,11 @@ row_log_online_op(
 	      == (op == ROW_OP_PURGE));
 #endif /* UNIV_SYNC_DEBUG */
 
-#ifdef UNIV_DEBUG
-	switch (op) {
-	case ROW_OP_INSERT:
-	case ROW_OP_DELETE_MARK:
-	case ROW_OP_DELETE_UNMARK:
-	case ROW_OP_DELETE_PURGE:
-		ut_ad(trx_id);
-		/* fall through */
-	case ROW_OP_PURGE:
-		goto op_ok;
-	}
-op_ok:
-#endif /* UNIV_DEBUG */
 	if (dict_index_is_corrupted(index)) {
 		return;
 	}
 
 	ut_ad(dict_index_is_online_ddl(index));
-	mutex_enter(&index->online_log->mutex);
-
-	if (trx_id > index->online_log->max_trx) {
-		index->online_log->max_trx = trx_id;
-	}
-
-	log = index->online_log;
-	UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf);
 
 	/* Compute the size of the record. This differs from
 	row_merge_buf_encode(), because here we do not encode
@@ -150,15 +129,33 @@ op_ok:
 	case ROW_OP_DELETE_MARK:
 	case ROW_OP_DELETE_UNMARK:
 	case ROW_OP_DELETE_PURGE:
+#ifdef UNIV_SYNC_DEBUG
+		ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+		ut_ad(trx_id);
 		mrec_size = ROW_LOG_HEADER_SIZE + DATA_TRX_ID_LEN
 			+ (extra_size >= 0x80) + size;
-		break;
+		goto op_ok;
 	case ROW_OP_PURGE:
+#ifdef UNIV_SYNC_DEBUG
+		ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
 		mrec_size = ROW_LOG_HEADER_SIZE
 			+ (extra_size >= 0x80) + size;
-		break;
+		goto op_ok;
 	}
 
+	ut_error;
+op_ok:
+	log = index->online_log;
+	mutex_enter(&log->mutex);
+
+	if (trx_id > log->max_trx) {
+		log->max_trx = trx_id;
+	}
+
+	UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf);
+
 	ut_ad(log->tail.bytes < srv_sort_buf_size);
 	avail_size = srv_sort_buf_size - log->tail.bytes;
 
@@ -215,7 +212,7 @@ op_ok:
 		UNIV_MEM_ASSERT_RW(log->tail.block, srv_sort_buf_size);
 		ret = os_file_write(
 			"(modification log)",
-			OS_FILE_FROM_FD(index->online_log->fd),
+			OS_FILE_FROM_FD(log->fd),
 			log->tail.block, byte_offset, srv_sort_buf_size);
 		log->tail.blocks++;
 		if (!ret) {
@@ -235,7 +232,7 @@ write_failed:
 	}
 
 	UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf);
-	mutex_exit(&index->online_log->mutex);
+	mutex_exit(&log->mutex);
 }
 
 /******************************************************//**
@@ -572,7 +569,7 @@ insert_the_rec:
 					BTR_NO_UNDO_LOG_FLAG
 					| BTR_NO_LOCKING_FLAG
 					| BTR_CREATE_FLAG,
-					&cursor,
+					&cursor, &offsets, &heap,
 					const_cast<dtuple_t*>(entry),
 					&rec, &big_rec,
 					0, NULL, &mtr);
@@ -599,7 +596,7 @@ insert_the_rec:
 				BTR_NO_UNDO_LOG_FLAG
 				| BTR_NO_LOCKING_FLAG
 				| BTR_CREATE_FLAG,
-				&cursor,
+				&cursor, &offsets, &heap,
 				const_cast<dtuple_t*>(entry),
 				&rec, &big_rec,
 				0, NULL, &mtr);

=== modified file 'storage/innobase/row/row0merge.cc'
--- a/storage/innobase/row/row0merge.cc	revid:marko.makela@stripped
+++ b/storage/innobase/row/row0merge.cc	revid:marko.makela@strippedom-20120523084804-es3dmpmzba8sy6ic
@@ -2155,6 +2155,7 @@ row_merge_insert_index_tuples(
 	const byte*		b;
 	mem_heap_t*		heap;
 	mem_heap_t*		tuple_heap;
+	mem_heap_t*		ins_heap;
 	dberr_t			error = DB_SUCCESS;
 	ulint			foffs = 0;
 	ulint*			offsets;
@@ -2170,6 +2171,7 @@ row_merge_insert_index_tuples(
 		ulint i	= 1 + REC_OFFS_HEADER_SIZE
 			+ dict_index_get_n_fields(index);
 		heap = mem_heap_create(sizeof *buf + i * sizeof *offsets);
+		ins_heap = mem_heap_create(sizeof *buf + i * sizeof *offsets);
 		offsets = static_cast<ulint*>(
 			mem_heap_alloc(heap, i * sizeof *offsets));
 		offsets[0] = i;
@@ -2246,12 +2248,13 @@ row_merge_insert_index_tuples(
 				      > 0);
 			}
 #endif /* UNIV_DEBUG */
+			ulint*	ins_offsets = NULL;
 
 			error = btr_cur_optimistic_insert(
 				BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
 				| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG,
-				&cursor, dtuple, &rec, &big_rec,
-				0, NULL, &mtr);
+				&cursor, &ins_offsets, &ins_heap,
+				dtuple, &rec, &big_rec, 0, NULL, &mtr);
 
 			if (error == DB_FAIL) {
 				ut_ad(!big_rec);
@@ -2270,8 +2273,8 @@ row_merge_insert_index_tuples(
 					BTR_NO_UNDO_LOG_FLAG
 					| BTR_NO_LOCKING_FLAG
 					| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG,
-					&cursor, dtuple, &rec, &big_rec,
-					0, NULL, &mtr);
+					&cursor, &ins_offsets, &ins_heap,
+					dtuple, &rec, &big_rec, 0, NULL, &mtr);
 			}
 
 			if (!dict_index_is_clust(index)) {
@@ -2294,7 +2297,8 @@ row_merge_insert_index_tuples(
 				ut_ad(dict_index_is_clust(index));
 				ut_ad(error == DB_SUCCESS);
 				error = row_ins_index_entry_big_rec(
-					dtuple, big_rec, offsets, &tuple_heap,
+					dtuple, big_rec,
+					ins_offsets, &ins_heap,
 					index, NULL, __FILE__, __LINE__);
 				dtuple_convert_back_big_rec(
 					index, dtuple, big_rec);
@@ -2305,11 +2309,13 @@ row_merge_insert_index_tuples(
 			}
 
 			mem_heap_empty(tuple_heap);
+			mem_heap_empty(ins_heap);
 		}
 	}
 
 err_exit:
 	mem_heap_free(tuple_heap);
+	mem_heap_free(ins_heap);
 	mem_heap_free(heap);
 
 	return(error);

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl6255 branch (marko.makela:3852 to 3855) WL#6255marko.makela23 May