List:Commits« Previous MessageNext Message »
From:marko.makela Date:May 21 2012 12:43pm
Subject:bzr push into mysql-trunk-wl6255 branch (marko.makela:3843 to 3847) WL#6255
View as plain text  
 3847 Marko Mäkelä	2012-05-21
      WL#6255 preparations to avoid adding rec_get_offsets() calls.
      
      The function rec_get_offsets() was added for MySQL 5.0.3 in a hurry.
      InnoDB reallocates and recomputes the offsets a few times per B-tree
      operation. We should really allocate the space for the offsets on
      page_cur creation, and we should keep the offsets up to date with
      page_cur.rec. This is not a complete fix, but it will avoid some cases
      of recomputing, so that WL#6255 will not add any rec_get_offsets()
      calls.
      
      btr_cur_upd_lock_and_undo(), btr_cur_update_in_place():
      Add the parameter offsets.
      
      btr_cur_update_in_place_log(): Add const qualifiers.
      
      btr_cur_optimistic_update(): Add the parameters offsets, heap, for
      keeping the result from rec_get_offsets(). TODO: Take the offsets from
      the caller.
      
      btr_cur_pessimistic_update(): Add the parameter offsets for keeping
      the result from rec_get_offsets(). TODO: Take the offsets from the
      caller.
      
      row_ins_index_entry_big_rec_func(): Declare the parameter offsets nonnull.
      
      row_ins_clust_index_entry_by_modify(): Add the parameter offsets for
      keeping the result from rec_get_offsets().
      
      row_undo_mod_clust_low(): Add the parameters offsets, heap, for
      keeping the result from rec_get_offsets(). TODO: Take the offsets from
      the caller.

    modified:
      storage/innobase/btr/btr0cur.cc
      storage/innobase/include/btr0cur.h
      storage/innobase/include/row0ins.h
      storage/innobase/row/row0ins.cc
      storage/innobase/row/row0log.cc
      storage/innobase/row/row0merge.cc
      storage/innobase/row/row0umod.cc
      storage/innobase/row/row0upd.cc
 3846 Marko Mäkelä	2012-05-21
      row_upd_clust_step(): Remove a local variable.

    modified:
      storage/innobase/row/row0upd.cc
 3845 Marko Mäkelä	2012-05-21
      row_rec_to_index_entry(): Re-validate offsets after the copying.

    modified:
      storage/innobase/include/row0row.h
      storage/innobase/row/row0row.cc
 3844 Marko Mäkelä	2012-05-21
      Add __attribute__.

    modified:
      storage/innobase/include/rem0rec.h
 3843 Marko Mäkelä	2012-05-17
      btr_cur_add_path_info(): Add const qualifiers.

    modified:
      storage/innobase/btr/btr0cur.cc
=== modified file 'storage/innobase/btr/btr0cur.cc'
--- a/storage/innobase/btr/btr0cur.cc	revid:marko.makela@stripped204133-y0mmf2zyqap05vt9
+++ b/storage/innobase/btr/btr0cur.cc	revid:marko.makela@stripped3lh5thcmg
@@ -1596,6 +1596,7 @@ btr_cur_upd_lock_and_undo(
 /*======================*/
 	ulint		flags,	/*!< in: undo logging and locking flags */
 	btr_cur_t*	cursor,	/*!< in: cursor on record to update */
+	const ulint*	offsets,/*!< in: rec_get_offsets() on cursor */
 	const upd_t*	update,	/*!< in: update vector */
 	ulint		cmpl_info,/*!< in: compiler info on secondary index
 				updates */
@@ -1605,7 +1606,7 @@ btr_cur_upd_lock_and_undo(
 	roll_ptr_t*	roll_ptr)/*!< out: roll pointer */
 {
 	dict_index_t*	index;
-	rec_t*		rec;
+	const rec_t*	rec;
 	dberr_t		err;
 
 	ut_ad(thr || (flags & BTR_NO_LOCKING_FLAG));
@@ -1614,6 +1615,7 @@ btr_cur_upd_lock_and_undo(
 	index = cursor->index;
 
 	ut_ad(dict_index_is_online_ddl(index) == !!(flags & BTR_CREATE_FLAG));
+	ut_ad(rec_offs_validate(rec, index, offsets));
 
 	if (!dict_index_is_clust(index)) {
 		/* We do undo logging only when we update a clustered index
@@ -1626,33 +1628,21 @@ btr_cur_upd_lock_and_undo(
 	/* Check if we have to wait for a lock: enqueue an explicit lock
 	request if yes */
 
-	mem_heap_t*	heap		= NULL;
-	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
-	ulint*		offsets;
-	rec_offs_init(offsets_);
-	offsets = rec_get_offsets(rec, index, offsets_,
-				  ULINT_UNDEFINED, &heap);
-
 	if (!(flags & BTR_NO_LOCKING_FLAG)) {
 		err = lock_clust_rec_modify_check_and_lock(
 			flags, btr_cur_get_block(cursor), rec, index,
 			offsets, thr);
 		if (err != DB_SUCCESS) {
-			goto func_exit;
+			return(err);
 		}
 	}
 
 	/* Append the info about the update in the undo log */
 
-	err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
-					    index, NULL, update,
-					    cmpl_info, rec, offsets, roll_ptr);
-func_exit:
-	if (UNIV_LIKELY_NULL(heap)) {
-		mem_heap_free(heap);
-	}
-
-	return(err);
+	return(trx_undo_report_row_operation(
+		       flags, TRX_UNDO_MODIFY_OP, thr,
+		       index, NULL, update,
+		       cmpl_info, rec, offsets, roll_ptr));
 }
 
 /***********************************************************//**
@@ -1662,15 +1652,15 @@ void
 btr_cur_update_in_place_log(
 /*========================*/
 	ulint		flags,		/*!< in: flags */
-	rec_t*		rec,		/*!< in: record */
+	const rec_t*	rec,		/*!< in: record */
 	dict_index_t*	index,		/*!< in: index of the record */
 	const upd_t*	update,		/*!< in: update vector */
 	trx_id_t	trx_id,		/*!< in: transaction id */
 	roll_ptr_t	roll_ptr,	/*!< in: roll ptr */
 	mtr_t*		mtr)		/*!< in: mtr */
 {
-	byte*	log_ptr;
-	page_t*	page	= page_align(rec);
+	byte*		log_ptr;
+	const page_t*	page	= page_align(rec);
 	ut_ad(flags < 256);
 	ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
 
@@ -1855,6 +1845,7 @@ btr_cur_update_in_place(
 	btr_cur_t*	cursor,	/*!< in: cursor on the record to update;
 				cursor stays valid and positioned on the
 				same record */
+	const ulint*	offsets,/*!< in: offsets on cursor->page_cur.rec */
 	const upd_t*	update,	/*!< in: update vector */
 	ulint		cmpl_info,/*!< in: compiler info on secondary index
 				updates */
@@ -1872,13 +1863,10 @@ btr_cur_update_in_place(
 	roll_ptr_t	roll_ptr	= 0;
 	ulint		was_delete_marked;
 	ibool		is_hashed;
-	mem_heap_t*	heap		= NULL;
-	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
-	ulint*		offsets		= offsets_;
-	rec_offs_init(offsets_);
 
 	rec = btr_cur_get_rec(cursor);
 	index = cursor->index;
+	ut_ad(rec_offs_validate(rec, index, offsets));
 	ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
 	/* The insert buffer tree should never be updated in place. */
 	ut_ad(!dict_index_is_ibuf(index));
@@ -1887,7 +1875,6 @@ btr_cur_update_in_place(
 	ut_ad(thr || flags == (BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
 			       | BTR_CREATE_FLAG | BTR_KEEP_SYS_FLAG));
 
-	offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 #ifdef UNIV_DEBUG
 	if (btr_cur_print_record_ops) {
 		btr_cur_trx_report(trx_id, index, "update ");
@@ -1906,13 +1893,11 @@ btr_cur_update_in_place(
 	}
 
 	/* Do lock checking and undo logging */
-	err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
+	err = btr_cur_upd_lock_and_undo(flags, cursor, offsets,
+					update, cmpl_info,
 					thr, mtr, &roll_ptr);
 	if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
 
-		if (UNIV_LIKELY_NULL(heap)) {
-			mem_heap_free(heap);
-		}
 		return(err);
 	}
 
@@ -1971,9 +1956,6 @@ btr_cur_update_in_place(
 					     rec, index, offsets, mtr);
 	}
 
-	if (UNIV_LIKELY_NULL(heap)) {
-		mem_heap_free(heap);
-	}
 	return(DB_SUCCESS);
 }
 
@@ -1994,6 +1976,8 @@ btr_cur_optimistic_update(
 	btr_cur_t*	cursor,	/*!< in: cursor on the record to update;
 				cursor stays valid and positioned on the
 				same record */
+	ulint**		offsets,/*!< out: offsets on cursor->page_cur.rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	const upd_t*	update,	/*!< in: update vector; this must also
 				contain trx id and roll ptr fields */
 	ulint		cmpl_info,/*!< in: compiler info on secondary index
@@ -2016,10 +2000,8 @@ btr_cur_optimistic_update(
 	ulint		old_rec_size;
 	dtuple_t*	new_entry;
 	roll_ptr_t	roll_ptr;
-	mem_heap_t*	heap;
 	ulint		i;
 	ulint		n_ext;
-	ulint*		offsets;
 
 	block = btr_cur_get_block(cursor);
 	page = buf_block_get_frame(block);
@@ -2034,39 +2016,37 @@ btr_cur_optimistic_update(
 	ut_ad(thr || flags == (BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
 			       | BTR_CREATE_FLAG | BTR_KEEP_SYS_FLAG));
 
-	heap = mem_heap_create(1024);
-	offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+	*offsets = rec_get_offsets(rec, index, *offsets,
+				   ULINT_UNDEFINED, heap);
 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
-	ut_a(!rec_offs_any_null_extern(rec, offsets)
+	ut_a(!rec_offs_any_null_extern(rec, *offsets)
 	     || trx_is_recv(thr_get_trx(thr)));
 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
 
 #ifdef UNIV_DEBUG
 	if (btr_cur_print_record_ops) {
 		btr_cur_trx_report(trx_id, index, "update ");
-		rec_print_new(stderr, rec, offsets);
+		rec_print_new(stderr, rec, *offsets);
 	}
 #endif /* UNIV_DEBUG */
 
-	if (!row_upd_changes_field_size_or_external(index, offsets, update)) {
+	if (!row_upd_changes_field_size_or_external(index, *offsets, update)) {
 
 		/* The simplest and the most common case: the update does not
 		change the size of any field and none of the updated fields is
 		externally stored in rec or update, and there is enough space
 		on the compressed page to log the update. */
 
-		mem_heap_free(heap);
 		return(btr_cur_update_in_place(
-			       flags, cursor, update,
+			       flags, cursor, *offsets, update,
 			       cmpl_info, thr, trx_id, mtr));
 	}
 
-	if (rec_offs_any_extern(offsets)) {
+	if (rec_offs_any_extern(*offsets)) {
 any_extern:
 		/* Externally stored fields are treated in pessimistic
 		update */
 
-		mem_heap_free(heap);
 		return(DB_OVERFLOW);
 	}
 
@@ -2079,8 +2059,8 @@ any_extern:
 
 	page_cursor = btr_cur_get_page_cur(cursor);
 
-	new_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
-					   &n_ext, heap);
+	new_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, *offsets,
+					   &n_ext, *heap);
 	/* We checked above that there are no externally stored fields. */
 	ut_a(!n_ext);
 
@@ -2088,8 +2068,8 @@ any_extern:
 	corresponding to new_entry is latched in mtr.
 	Thus the following call is safe. */
 	row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
-						     FALSE, heap);
-	old_rec_size = rec_offs_size(offsets);
+						     FALSE, *heap);
+	old_rec_size = rec_offs_size(*offsets);
 	new_rec_size = rec_get_converted_size(index, new_entry, 0);
 
 	page_zip = buf_block_get_page_zip(block);
@@ -2100,16 +2080,14 @@ any_extern:
 	if (page_zip
 	    && !btr_cur_update_alloc_zip(page_zip, block, index,
 					 new_rec_size, TRUE, mtr)) {
-		err = DB_ZIP_OVERFLOW;
-		goto err_exit;
+		return(DB_ZIP_OVERFLOW);
 	}
 
 	if (UNIV_UNLIKELY(new_rec_size
 			  >= (page_get_free_space_of_empty(page_is_comp(page))
 			      / 2))) {
 
-		err = DB_OVERFLOW;
-		goto err_exit;
+		return(DB_OVERFLOW);
 	}
 
 	if (UNIV_UNLIKELY(page_get_data_size(page)
@@ -2118,8 +2096,7 @@ any_extern:
 
 		/* The page would become too empty */
 
-		err = DB_UNDERFLOW;
-		goto err_exit;
+		return(DB_UNDERFLOW);
 	}
 
 	max_size = old_rec_size
@@ -2133,16 +2110,16 @@ any_extern:
 		reorganize: for simplicity, we decide what to do assuming a
 		reorganization is needed, though it might not be necessary */
 
-		err = DB_OVERFLOW;
-		goto err_exit;
+		return(DB_OVERFLOW);
 	}
 
 	/* Do lock checking and undo logging */
-	err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
+	err = btr_cur_upd_lock_and_undo(flags, cursor, *offsets,
+					update, cmpl_info,
 					thr, mtr, &roll_ptr);
 	if (err != DB_SUCCESS) {
 
-		goto err_exit;
+		return(err);
 	}
 
 	/* Ok, we may do the replacement. Store on the page infimum the
@@ -2156,10 +2133,10 @@ any_extern:
 	/* The call to row_rec_to_index_entry(ROW_COPY_DATA, ...) above
 	invokes rec_offs_make_valid() to point to the copied record that
 	the fields of new_entry point to.  We have to undo it here. */
-	ut_ad(rec_offs_validate(NULL, index, offsets));
-	rec_offs_make_valid(page_cur_get_rec(page_cursor), index, offsets);
+	ut_ad(rec_offs_validate(NULL, index, *offsets));
+	rec_offs_make_valid(page_cur_get_rec(page_cursor), index, *offsets);
 
-	page_cur_delete_rec(page_cursor, index, offsets, mtr);
+	page_cur_delete_rec(page_cursor, index, *offsets, mtr);
 
 	page_cur_move_to_prev(page_cursor);
 
@@ -2186,10 +2163,7 @@ any_extern:
 
 	page_cur_move_to_next(page_cursor);
 
-	err = DB_SUCCESS;
-err_exit:
-	mem_heap_free(heap);
-	return(err);
+	return(DB_SUCCESS);
 }
 
 /*************************************************************//**
@@ -2256,6 +2230,7 @@ btr_cur_pessimistic_update(
 	btr_cur_t*	cursor,	/*!< in/out: cursor on the record to update;
 				cursor may become invalid if *big_rec == NULL
 				|| !(flags & BTR_KEEP_POS_FLAG) */
+	ulint**		offsets,/*!< out: offsets on cursor->page_cur.rec */
 	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	big_rec_t**	big_rec,/*!< out: big rec vector whose fields have to
 				be stored externally by the caller, or NULL */
@@ -2286,8 +2261,8 @@ btr_cur_pessimistic_update(
 	ulint		n_extents	= 0;
 	ulint		n_reserved;
 	ulint		n_ext;
-	ulint*		offsets		= NULL;
 
+	*offsets = NULL;
 	*big_rec = NULL;
 
 	block = btr_cur_get_block(cursor);
@@ -2309,8 +2284,9 @@ btr_cur_pessimistic_update(
 	ut_ad(thr || flags == (BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
 			       | BTR_CREATE_FLAG | BTR_KEEP_SYS_FLAG));
 
-	optim_err = btr_cur_optimistic_update(flags, cursor, update,
-					      cmpl_info, thr, trx_id, mtr);
+	optim_err = btr_cur_optimistic_update(
+		flags, cursor, offsets, heap, update,
+		cmpl_info, thr, trx_id, mtr);
 
 	switch (optim_err) {
 	case DB_UNDERFLOW:
@@ -2322,7 +2298,8 @@ btr_cur_pessimistic_update(
 	}
 
 	/* Do lock checking and undo logging */
-	err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
+	err = btr_cur_upd_lock_and_undo(flags, cursor, *offsets,
+					update, cmpl_info,
 					thr, mtr, &roll_ptr);
 	if (err != DB_SUCCESS) {
 
@@ -2353,15 +2330,16 @@ btr_cur_pessimistic_update(
 	if (!*heap) {
 		*heap = mem_heap_create(1024);
 	}
-	offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, heap);
+	*offsets = rec_get_offsets(
+		rec, index, *offsets, ULINT_UNDEFINED, heap);
 
-	new_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
+	new_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, *offsets,
 					   &n_ext, *heap);
 	/* The call to row_rec_to_index_entry(ROW_COPY_DATA, ...) above
 	invokes rec_offs_make_valid() to point to the copied record that
 	the fields of new_entry point to.  We have to undo it here. */
-	ut_ad(rec_offs_validate(NULL, index, offsets));
-	rec_offs_make_valid(rec, index, offsets);
+	ut_ad(rec_offs_validate(NULL, index, *offsets));
+	rec_offs_make_valid(rec, index, *offsets);
 
 	/* The page containing the clustered index record
 	corresponding to new_entry is latched in mtr.  If the
@@ -2378,7 +2356,7 @@ btr_cur_pessimistic_update(
 					      trx_id);
 	}
 
-	if ((flags & BTR_NO_UNDO_LOG_FLAG) && rec_offs_any_extern(offsets)) {
+	if ((flags & BTR_NO_UNDO_LOG_FLAG) && rec_offs_any_extern(*offsets)) {
 		/* We are in a transaction rollback undoing a row
 		update: we must free possible externally stored fields
 		which got new values in the update, if they are not
@@ -2389,7 +2367,7 @@ btr_cur_pessimistic_update(
 		ut_ad(big_rec_vec == NULL);
 
 		btr_rec_free_updated_extern_fields(
-			index, rec, page_zip, offsets, update,
+			index, rec, page_zip, *offsets, update,
 			trx_is_recv(thr_get_trx(thr))
 			? RB_RECOVERY : RB_NORMAL, mtr);
 	}
@@ -2398,7 +2376,7 @@ btr_cur_pessimistic_update(
 	record to be inserted: we have to remember which fields were such */
 
 	ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
-	ut_ad(rec_offs_validate(rec, index, offsets));
+	ut_ad(rec_offs_validate(rec, index, *offsets));
 	n_ext += btr_push_update_extern_fields(new_entry, update, *heap);
 
 	if (page_zip) {
@@ -2445,7 +2423,7 @@ make_external:
 #endif /* UNIV_ZIP_DEBUG */
 	page_cursor = btr_cur_get_page_cur(cursor);
 
-	page_cur_delete_rec(page_cursor, index, offsets, mtr);
+	page_cur_delete_rec(page_cursor, index, *offsets, mtr);
 
 	page_cur_move_to_prev(page_cursor);
 
@@ -2457,14 +2435,14 @@ 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);
+		*offsets = rec_get_offsets(rec, index, *offsets,
+					   ULINT_UNDEFINED, heap);
 
-		if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
+		if (!rec_get_deleted_flag(rec, rec_offs_comp(*offsets))) {
 			/* The new inserted record owns its possible externally
 			stored fields */
-			btr_cur_unmark_extern_fields(page_zip,
-						     rec, index, offsets, mtr);
+			btr_cur_unmark_extern_fields(
+				page_zip, rec, index, *offsets, mtr);
 		}
 
 		btr_cur_compress_if_useful(
@@ -2535,7 +2513,7 @@ make_external:
 				       trx_id, mtr);
 	}
 
-	if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
+	if (!rec_get_deleted_flag(rec, rec_offs_comp(*offsets))) {
 		/* The new inserted record owns its possible externally
 		stored fields */
 		buf_block_t*	rec_block = btr_cur_get_block(cursor);
@@ -2546,10 +2524,10 @@ 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);
+		*offsets = rec_get_offsets(rec, index, *offsets,
+					   ULINT_UNDEFINED, heap);
 		btr_cur_unmark_extern_fields(page_zip,
-					     rec, index, offsets, mtr);
+					     rec, index, *offsets, mtr);
 	}
 
 	lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor),

=== modified file 'storage/innobase/include/btr0cur.h'
--- a/storage/innobase/include/btr0cur.h	revid:marko.makela@stripped9
+++ b/storage/innobase/include/btr0cur.h	revid:marko.makela@stripped
@@ -281,6 +281,7 @@ btr_cur_update_in_place(
 	btr_cur_t*	cursor,	/*!< in: cursor on the record to update;
 				cursor stays valid and positioned on the
 				same record */
+	const ulint*	offsets,/*!< in: offsets on cursor->page_cur.rec */
 	const upd_t*	update,	/*!< in: update vector */
 	ulint		cmpl_info,/*!< in: compiler info on secondary index
 				updates */
@@ -289,7 +290,7 @@ btr_cur_update_in_place(
 	trx_id_t	trx_id,	/*!< in: transaction id */
 	mtr_t*		mtr)	/*!< in: mtr; must be committed before
 				latching any further pages */
-	__attribute__((warn_unused_result, nonnull(2,3,7)));
+	__attribute__((warn_unused_result, nonnull(2,3,4,8)));
 /*************************************************************//**
 Tries to update a record on a page in an index tree. It is assumed that mtr
 holds an x-latch on the page. The operation does not succeed if there is too
@@ -306,6 +307,8 @@ btr_cur_optimistic_update(
 	btr_cur_t*	cursor,	/*!< in: cursor on the record to update;
 				cursor stays valid and positioned on the
 				same record */
+	ulint**		offsets,/*!< out: offsets on cursor->page_cur.rec */
+	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	const upd_t*	update,	/*!< in: update vector; this must also
 				contain trx id and roll ptr fields */
 	ulint		cmpl_info,/*!< in: compiler info on secondary index
@@ -315,7 +318,7 @@ btr_cur_optimistic_update(
 	trx_id_t	trx_id,	/*!< in: transaction id */
 	mtr_t*		mtr)	/*!< in: mtr; must be committed before
 				latching any further pages */
-	__attribute__((warn_unused_result, nonnull(2,3,7)));
+	__attribute__((warn_unused_result, nonnull(2,3,4,5,9)));
 /*************************************************************//**
 Performs an update of a record on a page of a tree. It is assumed
 that mtr holds an x-latch on the tree and on the cursor page. If the
@@ -331,6 +334,7 @@ btr_cur_pessimistic_update(
 	btr_cur_t*	cursor,	/*!< in/out: cursor on the record to update;
 				cursor may become invalid if *big_rec == NULL
 				|| !(flags & BTR_KEEP_POS_FLAG) */
+	ulint**		offsets,/*!< out: offsets on cursor->page_cur.rec */
 	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	big_rec_t**	big_rec,/*!< out: big rec vector whose fields have to
 				be stored externally by the caller, or NULL */
@@ -344,7 +348,7 @@ btr_cur_pessimistic_update(
 	trx_id_t	trx_id,	/*!< in: transaction id */
 	mtr_t*		mtr)	/*!< in: mtr; must be committed before
 				latching any further pages */
-	__attribute__((warn_unused_result, nonnull(2,5,9)));
+	__attribute__((warn_unused_result, nonnull(2,3,4,5,6,10)));
 /***********************************************************//**
 Marks a clustered index record deleted. Writes an undo log record to
 undo log on this delete marking. Writes in the trx id field the id

=== modified file 'storage/innobase/include/rem0rec.h'
--- a/storage/innobase/include/rem0rec.h	revid:marko.makela@strippedvt9
+++ b/storage/innobase/include/rem0rec.h	revid:marko.makela@stripped
@@ -356,7 +356,8 @@ rec_get_offsets_func(
 					 (ULINT_UNDEFINED if all fields) */
 	mem_heap_t**		heap,	/*!< in/out: memory heap */
 	const char*		file,	/*!< in: file name where called */
-	ulint			line);	/*!< in: line number where called */
+	ulint			line)	/*!< in: line number where called */
+	__attribute__((nonnull(1,2,5,6),warn_unused_result));
 
 #define rec_get_offsets(rec,index,offsets,n,heap)	\
 	rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)

=== modified file 'storage/innobase/include/row0ins.h'
--- a/storage/innobase/include/row0ins.h	revid:marko.makela@stripped
+++ b/storage/innobase/include/row0ins.h	revid:marko.makela@stripped
@@ -121,7 +121,7 @@ row_ins_index_entry_big_rec_func(
 	const void*		thd,	/*!< in: connection, or NULL */
 #endif /* DBUG_OFF */
 	ulint			line)	/*!< in: line number of caller */
-	__attribute__((nonnull(1,2,4,5,6), warn_unused_result));
+	__attribute__((nonnull(1,2,3,4,5,6), warn_unused_result));
 #ifdef DBUG_OFF
 # define row_ins_index_entry_big_rec(e,big,ofs,heap,index,thd,file,line) \
 	row_ins_index_entry_big_rec_func(e,big,ofs,heap,index,file,line)

=== modified file 'storage/innobase/include/row0row.h'
--- a/storage/innobase/include/row0row.h	revid:marko.makela@oracle.com-20120517204133-y0mmf2zyqap05vt9
+++ b/storage/innobase/include/row0row.h	revid:marko.makela@stripped21083407-cc8ul313lh5thcmg
@@ -146,8 +146,9 @@ row_build(
 	row_ext_t**		ext,	/*!< out, own: cache of
 					externally stored column
 					prefixes, or NULL */
-	mem_heap_t*		heap);	/*!< in: memory heap from which
+	mem_heap_t*		heap)	/*!< in: memory heap from which
 					the memory needed is allocated */
+	__attribute__((nonnull(2,3,7), warn_unused_result));
 /*******************************************************************//**
 Converts an index record to a typed data tuple.
 @return index entry built; does not set info_bits, and the data fields
@@ -161,8 +162,9 @@ row_rec_to_index_entry_low(
 	const ulint*		offsets,/*!< in: rec_get_offsets(rec, index) */
 	ulint*			n_ext,	/*!< out: number of externally
 					stored columns */
-	mem_heap_t*		heap);	/*!< in: memory heap from which
+	mem_heap_t*		heap)	/*!< in: memory heap from which
 					the memory needed is allocated */
+	__attribute__((nonnull, warn_unused_result));
 /*******************************************************************//**
 Converts an index record to a typed data tuple. NOTE that externally
 stored (often big) fields are NOT copied to heap.
@@ -190,8 +192,9 @@ row_rec_to_index_entry(
 	ulint*			offsets,/*!< in/out: rec_get_offsets(rec) */
 	ulint*			n_ext,	/*!< out: number of externally
 					stored columns */
-	mem_heap_t*		heap);	/*!< in: memory heap from which
+	mem_heap_t*		heap)	/*!< in: memory heap from which
 					the memory needed is allocated */
+	__attribute__((nonnull, warn_unused_result));
 /*******************************************************************//**
 Builds from a secondary index record a row reference with which we can
 search the clustered index record.
@@ -212,8 +215,9 @@ row_build_row_ref(
 				the buffer page of this record must be
 				at least s-latched and the latch held
 				as long as the row reference is used! */
-	mem_heap_t*	heap);	/*!< in: memory heap from which the memory
+	mem_heap_t*	heap)	/*!< in: memory heap from which the memory
 				needed is allocated */
+	__attribute__((nonnull, warn_unused_result));
 /*******************************************************************//**
 Builds from a secondary index record a row reference with which we can
 search the clustered index record. */
@@ -234,7 +238,8 @@ row_build_row_ref_in_tuple(
 	const dict_index_t*	index,	/*!< in: secondary index */
 	ulint*			offsets,/*!< in: rec_get_offsets(rec, index)
 					or NULL */
-	trx_t*			trx);	/*!< in: transaction */
+	trx_t*			trx)	/*!< in: transaction or NULL */
+	__attribute__((nonnull(1,2,3)));
 /*******************************************************************//**
 Builds from a secondary index record a row reference with which we can
 search the clustered index record. */
@@ -264,7 +269,8 @@ row_search_on_row_ref(
 	ulint			mode,	/*!< in: BTR_MODIFY_LEAF, ... */
 	const dict_table_t*	table,	/*!< in: table */
 	const dtuple_t*		ref,	/*!< in: row reference */
-	mtr_t*			mtr);	/*!< in/out: mtr */
+	mtr_t*			mtr)	/*!< in/out: mtr */
+	__attribute__((nonnull, warn_unused_result));
 /*********************************************************************//**
 Fetches the clustered index record for a secondary index record. The latches
 on the secondary index record are preserved.
@@ -277,7 +283,8 @@ row_get_clust_rec(
 	const rec_t*	rec,	/*!< in: record in a secondary index */
 	dict_index_t*	index,	/*!< in: secondary index */
 	dict_index_t**	clust_index,/*!< out: clustered index */
-	mtr_t*		mtr);	/*!< in: mtr */
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull, warn_unused_result));
 
 /** Result of row_search_index_entry */
 enum row_search_result {
@@ -304,8 +311,8 @@ row_search_index_entry(
 	ulint		mode,	/*!< in: BTR_MODIFY_LEAF, ... */
 	btr_pcur_t*	pcur,	/*!< in/out: persistent cursor, which must
 				be closed by the caller */
-	mtr_t*		mtr);	/*!< in: mtr */
-
+	mtr_t*		mtr)	/*!< in: mtr */
+	__attribute__((nonnull, warn_unused_result));
 
 #define ROW_COPY_DATA		1
 #define ROW_COPY_POINTERS	2
@@ -332,8 +339,9 @@ row_raw_format(
 						in bytes */
 	const dict_field_t*	dict_field,	/*!< in: index field */
 	char*			buf,		/*!< out: output buffer */
-	ulint			buf_size);	/*!< in: output buffer size
+	ulint			buf_size)	/*!< in: output buffer size
 						in bytes */
+	__attribute__((nonnull, warn_unused_result));
 
 #ifndef UNIV_NONINL
 #include "row0row.ic"

=== modified file 'storage/innobase/row/row0ins.cc'
--- a/storage/innobase/row/row0ins.cc	revid:marko.makela@stripped
+++ b/storage/innobase/row/row0ins.cc	revid:marko.makela@oracle.com-20120521083407-cc8ul313lh5thcmg
@@ -243,7 +243,7 @@ row_ins_sec_index_entry_by_modify(
 	mem_heap_t*	heap;
 	upd_t*		update;
 	rec_t*		rec;
-	const ulint*	offsets;
+	ulint*		offsets;
 	dberr_t		err;
 
 	rec = btr_cur_get_rec(cursor);
@@ -270,9 +270,11 @@ row_ins_sec_index_entry_by_modify(
 		/* Try an optimistic updating of the record, keeping changes
 		within the page */
 
-		err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor,
-						update, 0, thr,
-						thr_get_trx(thr)->id, mtr);
+		/* TODO: pass only offsets, no &offsets, &heap */
+		err = btr_cur_optimistic_update(
+			BTR_KEEP_SYS_FLAG, cursor,
+			&offsets, &heap, update, 0, thr,
+			thr_get_trx(thr)->id, mtr);
 		switch (err) {
 		case DB_OVERFLOW:
 		case DB_UNDERFLOW:
@@ -290,10 +292,10 @@ row_ins_sec_index_entry_by_modify(
 			goto func_exit;
 		}
 
-		err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor,
-						 &heap, &dummy_big_rec, update,
-						 0, thr,
-						 thr_get_trx(thr)->id, mtr);
+		err = btr_cur_pessimistic_update(
+			BTR_KEEP_SYS_FLAG, cursor,
+			&offsets, &heap, &dummy_big_rec, update, 0, thr,
+			thr_get_trx(thr)->id, mtr);
 		ut_ad(!dummy_big_rec);
 	}
 func_exit:
@@ -315,6 +317,7 @@ row_ins_clust_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,/*!< out: offsets on cursor->page_cur.rec */
 	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	big_rec_t**	big_rec,/*!< out: possible big rec vector of fields
 				which have to be stored externally by the
@@ -351,8 +354,9 @@ row_ins_clust_index_entry_by_modify(
 		/* Try optimistic updating of the record, keeping changes
 		within the page */
 
-		err = btr_cur_optimistic_update(0, cursor, update, 0, thr,
-						thr_get_trx(thr)->id, mtr);
+		err = btr_cur_optimistic_update(
+			0, cursor, offsets, heap, update, 0, thr,
+			thr_get_trx(thr)->id, mtr);
 		switch (err) {
 		case DB_OVERFLOW:
 		case DB_UNDERFLOW:
@@ -369,7 +373,8 @@ row_ins_clust_index_entry_by_modify(
 
 		}
 		err = btr_cur_pessimistic_update(
-			BTR_KEEP_POS_FLAG, cursor, heap, big_rec, update,
+			BTR_KEEP_POS_FLAG,
+			cursor, offsets, heap, big_rec, update,
 			0, thr, thr_get_trx(thr)->id, mtr);
 	}
 
@@ -2142,12 +2147,12 @@ row_ins_clust_index_entry_low(
 {
 	btr_cur_t	cursor;
 	rec_t*		rec;
-	ulint*		offsets;
+	ulint*		offsets		= NULL;
 	dberr_t		err;
 	ulint		n_unique;
-	big_rec_t*	big_rec			= NULL;
+	big_rec_t*	big_rec		= NULL;
 	mtr_t		mtr;
-	mem_heap_t*	heap			= NULL;
+	mem_heap_t*	heap		= NULL;
 
 	ut_ad(dict_index_is_clust(index));
 
@@ -2199,7 +2204,7 @@ err_exit:
 		existing record */
 
 		err = row_ins_clust_index_entry_by_modify(
-			mode, &cursor, &heap, &big_rec, entry,
+			mode, &cursor, &offsets, &heap, &big_rec, entry,
 			thr, &mtr);
 
 		if (big_rec) {
@@ -2229,9 +2234,6 @@ err_exit:
 			truncated in the crash. */
 
 			rec = btr_cur_get_rec(&cursor);
-			offsets = rec_get_offsets(
-				rec, index, NULL,
-				ULINT_UNDEFINED, &heap);
 
 			DEBUG_SYNC_C_IF_THD(
 				thr_get_trx(thr)->mysql_thd,
@@ -2292,7 +2294,7 @@ err_exit:
 				log_make_checkpoint_at(
 					IB_ULONGLONG_MAX, TRUE););
 			err = row_ins_index_entry_big_rec(
-				entry, big_rec, NULL, &heap, index,
+				entry, big_rec, offsets, &heap, index,
 				thr_get_trx(thr)->mysql_thd,
 				__FILE__, __LINE__);
 			dtuple_convert_back_big_rec(index, entry, big_rec);

=== modified file 'storage/innobase/row/row0log.cc'
--- a/storage/innobase/row/row0log.cc	revid:marko.makela@stripped20517204133-y0mmf2zyqap05vt9
+++ b/storage/innobase/row/row0log.cc	revid:marko.makela@stripped8ul313lh5thcmg
@@ -331,6 +331,7 @@ row_log_apply_op_low(
 {
 	mtr_t		mtr;
 	btr_cur_t	cursor;
+	ulint*		offsets = NULL;
 
 	ut_ad(!dict_index_is_clust(index));
 #ifdef UNIV_SYNC_DEBUG
@@ -362,7 +363,6 @@ row_log_apply_op_low(
 		rec_t*		rec	= btr_cur_get_rec(&cursor);
 		ulint		deleted	= rec_get_deleted_flag(
 			rec, page_rec_is_comp(rec));
-		const ulint*	offsets;
 		upd_t*		update;
 		big_rec_t*	big_rec;
 
@@ -469,13 +469,14 @@ update_the_rec:
 				| entry->info_bits;
 
 			if (!has_index_lock) {
+				/* TODO: pass offsets, not &offsets */
 				*error = btr_cur_optimistic_update(
 					BTR_NO_UNDO_LOG_FLAG
 					| BTR_NO_LOCKING_FLAG
 					| BTR_CREATE_FLAG
 					| BTR_KEEP_SYS_FLAG,
-					&cursor, update, 0, NULL,
-					trx_id, &mtr);
+					&cursor, &offsets, &heap,
+					update, 0, NULL, trx_id, &mtr);
 
 				if (*error != DB_FAIL) {
 					break;
@@ -505,7 +506,7 @@ update_the_rec:
 				| BTR_NO_LOCKING_FLAG
 				| BTR_CREATE_FLAG
 				| BTR_KEEP_SYS_FLAG,
-				&cursor, &heap, &big_rec,
+				&cursor, &offsets, &heap, &big_rec,
 				update, 0, NULL, trx_id, &mtr);
 			ut_ad(!big_rec);
 			break;
@@ -549,7 +550,8 @@ insert_the_rec:
 					BTR_NO_UNDO_LOG_FLAG
 					| BTR_NO_LOCKING_FLAG
 					| BTR_CREATE_FLAG,
-					&cursor, const_cast<dtuple_t*>(entry),
+					&cursor,
+					const_cast<dtuple_t*>(entry),
 					&rec, &big_rec,
 					0, NULL, &mtr);
 				ut_ad(!big_rec);
@@ -575,7 +577,8 @@ insert_the_rec:
 				BTR_NO_UNDO_LOG_FLAG
 				| BTR_NO_LOCKING_FLAG
 				| BTR_CREATE_FLAG,
-				&cursor, const_cast<dtuple_t*>(entry),
+				&cursor,
+				const_cast<dtuple_t*>(entry),
 				&rec, &big_rec,
 				0, NULL, &mtr);
 			ut_ad(!big_rec);

=== 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@oracle.com-20120521083407-cc8ul313lh5thcmg
@@ -2304,7 +2304,7 @@ 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, NULL, &tuple_heap,
+					dtuple, big_rec, offsets, &tuple_heap,
 					index, NULL, __FILE__, __LINE__);
 				dtuple_convert_back_big_rec(
 					index, dtuple, big_rec);

=== modified file 'storage/innobase/row/row0row.cc'
--- a/storage/innobase/row/row0row.cc	revid:marko.makela@oracle.com-20120517204133-y0mmf2zyqap05vt9
+++ b/storage/innobase/row/row0row.cc	revid:marko.makela@stripped0521083407-cc8ul313lh5thcmg
@@ -437,6 +437,7 @@ row_rec_to_index_entry(
 {
 	dtuple_t*	entry;
 	byte*		buf;
+	const rec_t*	copy_rec;
 
 	ut_ad(rec && heap && index);
 	ut_ad(rec_offs_validate(rec, index, offsets));
@@ -446,16 +447,18 @@ row_rec_to_index_entry(
 		buf = static_cast<byte*>(
 			mem_heap_alloc(heap, rec_offs_size(offsets)));
 
-		rec = rec_copy(buf, rec, offsets);
-		/* Avoid a debug assertion in rec_offs_validate(). */
-		rec_offs_make_valid(rec, index, offsets);
-#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
+		copy_rec = rec_copy(buf, rec, offsets);
 	} else {
+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
 		ut_a(!rec_offs_any_null_extern(rec, offsets));
 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
+		copy_rec = rec;
 	}
 
-	entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
+	rec_offs_make_valid(copy_rec, index, offsets);
+	entry = row_rec_to_index_entry_low(
+		copy_rec, index, offsets, n_ext, heap);
+	rec_offs_make_valid(rec, index, offsets);
 
 	dtuple_set_info_bits(entry,
 			     rec_get_info_bits(rec, rec_offs_comp(offsets)));

=== modified file 'storage/innobase/row/row0umod.cc'
--- a/storage/innobase/row/row0umod.cc	revid:marko.makela@strippedf2zyqap05vt9
+++ b/storage/innobase/row/row0umod.cc	revid:marko.makela@stripped
@@ -106,6 +106,8 @@ dberr_t
 row_undo_mod_clust_low(
 /*===================*/
 	undo_node_t*	node,	/*!< in: row undo node */
+	ulint**		offsets,/*!< out: rec_get_offsets() on the record */
+	mem_heap_t*	heap,	/*!< in/out: memory heap */
 	que_thr_t*	thr,	/*!< in: query thread */
 	mtr_t*		mtr,	/*!< in: mtr; must be committed before
 				latching any further pages */
@@ -118,7 +120,7 @@ row_undo_mod_clust_low(
 	ibool		success;
 #endif /* UNIV_DEBUG */
 
-	pcur = &(node->pcur);
+	pcur = &node->pcur;
 	btr_cur = btr_pcur_get_btr_cur(pcur);
 
 #ifdef UNIV_DEBUG
@@ -133,15 +135,14 @@ row_undo_mod_clust_low(
 	      == thr_get_trx(thr)->id);
 
 	if (mode == BTR_MODIFY_LEAF) {
-
 		err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG
 						| BTR_NO_UNDO_LOG_FLAG
 						| BTR_KEEP_SYS_FLAG,
-						btr_cur, node->update,
+						btr_cur,
+						offsets, &heap, node->update,
 						node->cmpl_info, thr,
 						thr_get_trx(thr)->id, mtr);
 	} else {
-		mem_heap_t*	heap		= NULL;
 		big_rec_t*	dummy_big_rec;
 
 		ut_ad(mode == BTR_MODIFY_TREE);
@@ -150,13 +151,10 @@ row_undo_mod_clust_low(
 			BTR_NO_LOCKING_FLAG
 			| BTR_NO_UNDO_LOG_FLAG
 			| BTR_KEEP_SYS_FLAG,
-			btr_cur, &heap, &dummy_big_rec, node->update,
+			btr_cur, offsets, &heap, &dummy_big_rec, node->update,
 			node->cmpl_info, thr, thr_get_trx(thr)->id, mtr);
 
 		ut_a(!dummy_big_rec);
-		if (UNIV_LIKELY_NULL(heap)) {
-			mem_heap_free(heap);
-		}
 	}
 
 	return(err);
@@ -256,10 +254,14 @@ row_undo_mod_clust(
 
 	mtr_start(&mtr);
 
+	mem_heap_t*	heap	= mem_heap_create(1024);
+	ulint*		offsets	= NULL;
+
 	/* Try optimistic processing of the record, keeping changes within
 	the index page */
 
-	err = row_undo_mod_clust_low(node, thr, &mtr, BTR_MODIFY_LEAF);
+	err = row_undo_mod_clust_low(node, &offsets, heap, thr, &mtr,
+				     BTR_MODIFY_LEAF);
 
 	if (err != DB_SUCCESS) {
 		btr_pcur_commit_specify_mtr(pcur, &mtr);
@@ -269,7 +271,9 @@ row_undo_mod_clust(
 
 		mtr_start(&mtr);
 
-		err = row_undo_mod_clust_low(node, thr, &mtr, BTR_MODIFY_TREE);
+		err = row_undo_mod_clust_low(node, &offsets, heap, thr, &mtr,
+					     BTR_MODIFY_TREE);
+		ut_ad(err == DB_SUCCESS || err == DB_OUT_OF_FILE_SPACE);
 	}
 
 	btr_pcur_commit_specify_mtr(pcur, &mtr);
@@ -278,8 +282,8 @@ row_undo_mod_clust(
 
 		mtr_start(&mtr);
 
-		err = row_undo_mod_remove_clust_low(node, thr, &mtr,
-						    BTR_MODIFY_LEAF);
+		err = row_undo_mod_remove_clust_low(
+			node, thr, &mtr, BTR_MODIFY_LEAF);
 		if (err != DB_SUCCESS) {
 			btr_pcur_commit_specify_mtr(pcur, &mtr);
 
@@ -290,6 +294,9 @@ row_undo_mod_clust(
 
 			err = row_undo_mod_remove_clust_low(node, thr, &mtr,
 							    BTR_MODIFY_TREE);
+
+			ut_ad(err == DB_SUCCESS
+			      || err == DB_OUT_OF_FILE_SPACE);
 		}
 
 		btr_pcur_commit_specify_mtr(pcur, &mtr);
@@ -313,6 +320,7 @@ row_undo_mod_clust(
 		}
 	}
 
+	mem_heap_free(heap);
 	return(err);
 }
 
@@ -509,7 +517,7 @@ row_undo_mod_del_unmark_sec_and_undo_upd
 
 	switch (search_result) {
 		mem_heap_t*	heap;
-		const ulint*	offsets;
+		ulint*		offsets;
 	case ROW_BUFFERED:
 	case ROW_NOT_DELETED_REF:
 		/* These are invalid outcomes, because the mode passed
@@ -555,9 +563,10 @@ row_undo_mod_del_unmark_sec_and_undo_upd
 			/* Try an optimistic updating of the record, keeping
 			changes within the page */
 
+			/* TODO: pass offsets, not &offsets */
 			err = btr_cur_optimistic_update(
 				BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG,
-				btr_cur, update, 0, thr,
+				btr_cur, &offsets, &heap, update, 0, thr,
 				thr_get_trx(thr)->id, &mtr);
 			switch (err) {
 			case DB_OVERFLOW:
@@ -571,7 +580,7 @@ row_undo_mod_del_unmark_sec_and_undo_upd
 			ut_a(mode == BTR_MODIFY_TREE);
 			err = btr_cur_pessimistic_update(
 				BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG,
-				btr_cur, &heap, &dummy_big_rec,
+				btr_cur, &offsets, &heap, &dummy_big_rec,
 				update, 0, thr, thr_get_trx(thr)->id, &mtr);
 			ut_a(!dummy_big_rec);
 		}
@@ -911,6 +920,8 @@ row_undo_mod(
 
 	row_undo_mod_parse_undo_rec(node, thr, dict_locked);
 
+	ut_ad(thr_get_trx(thr) == node->trx);
+
 	if (node->table == NULL) {
 		/* It is already undone, or will be undone by another query
 		thread, or table was dropped */

=== modified file 'storage/innobase/row/row0upd.cc'
--- a/storage/innobase/row/row0upd.cc	revid:marko.makela@strippedap05vt9
+++ b/storage/innobase/row/row0upd.cc	revid:marko.makela@stripped
@@ -2038,6 +2038,7 @@ err_exit:
 		offsets = rec_get_offsets(rec, index, offsets,
 					  ULINT_UNDEFINED, &heap);
 		ut_ad(page_rec_is_user_rec(rec));
+		ut_ad(rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
 
 		btr_cur_disown_inherited_fields(
 			btr_cur_get_page_zip(btr_cur),
@@ -2065,11 +2066,12 @@ row_upd_clust_rec(
 	que_thr_t*	thr,	/*!< in: query thread */
 	mtr_t*		mtr)	/*!< in: mtr; gets committed here */
 {
-	mem_heap_t*	heap	= NULL;
+	mem_heap_t*	heap;
 	big_rec_t*	big_rec	= NULL;
 	btr_pcur_t*	pcur;
 	btr_cur_t*	btr_cur;
 	dberr_t		err;
+	ulint*		offsets	= NULL;
 
 	ut_ad(node);
 	ut_ad(dict_index_is_clust(index));
@@ -2077,20 +2079,30 @@ row_upd_clust_rec(
 	pcur = node->pcur;
 	btr_cur = btr_pcur_get_btr_cur(pcur);
 
+	ut_ad(btr_cur_get_index(btr_cur) == index);
 	ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
 				    dict_table_is_comp(index->table)));
 
+	heap = mem_heap_create(1024);
+
 	/* Try optimistic updating of the record, keeping changes within
 	the page; we do not check locks because we assume the x-lock on the
 	record to update */
 
 	if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
+		/* TODO: reuse offsets from caller */
+		offsets = rec_get_offsets(
+			btr_cur_get_rec(btr_cur),
+			index, offsets, ULINT_UNDEFINED, &heap);
+
 		err = btr_cur_update_in_place(
-			BTR_NO_LOCKING_FLAG, btr_cur, node->update,
+			BTR_NO_LOCKING_FLAG, btr_cur,
+			offsets, node->update,
 			node->cmpl_info, thr, thr_get_trx(thr)->id, mtr);
 	} else {
 		err = btr_cur_optimistic_update(
-			BTR_NO_LOCKING_FLAG, btr_cur, node->update,
+			BTR_NO_LOCKING_FLAG, btr_cur,
+			&offsets, &heap, node->update,
 			node->cmpl_info, thr, thr_get_trx(thr)->id, mtr);
 	}
 
@@ -2098,12 +2110,13 @@ row_upd_clust_rec(
 
 	if (UNIV_LIKELY(err == DB_SUCCESS)) {
 
-		return(DB_SUCCESS);
+		goto func_exit;
 	}
 
 	if (buf_LRU_buf_pool_running_out()) {
 
-		return(DB_LOCK_TABLE_FULL);
+		err = DB_LOCK_TABLE_FULL;
+		goto func_exit;
 	}
 	/* We may have to modify the tree structure: do a pessimistic descent
 	down the index tree */
@@ -2123,13 +2136,9 @@ row_upd_clust_rec(
 
 	err = btr_cur_pessimistic_update(
 		BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur,
-		&heap, &big_rec, node->update, node->cmpl_info,
+		&offsets, &heap, &big_rec, node->update, node->cmpl_info,
 		thr, thr_get_trx(thr)->id, mtr);
 	if (big_rec) {
-		ulint	offsets_[REC_OFFS_NORMAL_SIZE];
-		rec_t*	rec;
-		rec_offs_init(offsets_);
-
 		ut_a(err == DB_SUCCESS);
 		/* Write out the externally stored
 		columns while still x-latching
@@ -2152,12 +2161,10 @@ row_upd_clust_rec(
 		portion of the file, in case the file was somehow
 		truncated in the crash. */
 
-		rec = btr_cur_get_rec(btr_cur);
 		DEBUG_SYNC_C("before_row_upd_extern");
 		err = btr_store_big_rec_extern_fields(
-			index, btr_cur_get_block(btr_cur), rec,
-			rec_get_offsets(rec, index, offsets_,
-					ULINT_UNDEFINED, &heap),
+			index, btr_cur_get_block(btr_cur),
+			btr_cur_get_rec(btr_cur), offsets,
 			big_rec, mtr, BTR_STORE_UPDATE);
 		DEBUG_SYNC_C("after_row_upd_extern");
 		/* If writing big_rec fails (for example, because of
@@ -2177,10 +2184,8 @@ row_upd_clust_rec(
 	}
 
 	mtr_commit(mtr);
-
-	if (UNIV_LIKELY_NULL(heap)) {
-		mem_heap_free(heap);
-	}
+func_exit:
+	mem_heap_free(heap);
 
 	if (big_rec) {
 		dtuple_big_rec_free(big_rec);
@@ -2255,8 +2260,7 @@ row_upd_clust_step(
 	btr_pcur_t*	pcur;
 	ibool		success;
 	dberr_t		err;
-	mtr_t*		mtr;
-	mtr_t		mtr_buf;
+	mtr_t		mtr;
 	rec_t*		rec;
 	mem_heap_t*	heap		= NULL;
 	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
@@ -2271,9 +2275,8 @@ row_upd_clust_step(
 	pcur = node->pcur;
 
 	/* We have to restore the cursor to its position */
-	mtr = &mtr_buf;
 
-	mtr_start(mtr);
+	mtr_start(&mtr);
 
 	/* If the restoration does not succeed, then the same
 	transaction has deleted the record on which the cursor was,
@@ -2285,12 +2288,12 @@ row_upd_clust_step(
 
 	ut_a(pcur->rel_pos == BTR_PCUR_ON);
 
-	success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
+	success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, &mtr);
 
 	if (!success) {
 		err = DB_RECORD_NOT_FOUND;
 
-		mtr_commit(mtr);
+		mtr_commit(&mtr);
 
 		return(err);
 	}
@@ -2301,18 +2304,18 @@ row_upd_clust_step(
 
 	if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
 
-		dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
+		dict_drop_index_tree(btr_pcur_get_rec(pcur), &mtr);
 
-		mtr_commit(mtr);
+		mtr_commit(&mtr);
 
-		mtr_start(mtr);
+		mtr_start(&mtr);
 
 		success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
-						    mtr);
+						    &mtr);
 		if (!success) {
 			err = DB_ERROR;
 
-			mtr_commit(mtr);
+			mtr_commit(&mtr);
 
 			return(err);
 		}
@@ -2327,7 +2330,7 @@ row_upd_clust_step(
 			0, btr_pcur_get_block(pcur),
 			rec, index, offsets, thr);
 		if (err != DB_SUCCESS) {
-			mtr_commit(mtr);
+			mtr_commit(&mtr);
 			goto exit_func;
 		}
 	}
@@ -2336,7 +2339,7 @@ row_upd_clust_step(
 
 	if (node->is_delete) {
 		err = row_upd_del_mark_clust_rec(
-			node, index, offsets, thr, referenced, mtr);
+			node, index, offsets, thr, referenced, &mtr);
 
 		if (err == DB_SUCCESS) {
 			node->state = UPD_NODE_UPDATE_ALL_SEC;
@@ -2366,7 +2369,7 @@ exit_func:
 
 	if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
 
-		return(row_upd_clust_rec(node, index, thr, mtr));
+		return(row_upd_clust_rec(node, index, thr, &mtr));
 	}
 
 	row_upd_store_row(node);
@@ -2386,7 +2389,7 @@ exit_func:
 		externally! */
 
 		err = row_upd_clust_rec_by_insert(
-			node, index, thr, referenced, mtr);
+			node, index, thr, referenced, &mtr);
 
 		if (err != DB_SUCCESS) {
 
@@ -2395,7 +2398,7 @@ exit_func:
 
 		node->state = UPD_NODE_UPDATE_ALL_SEC;
 	} else {
-		err = row_upd_clust_rec(node, index, thr, mtr);
+		err = row_upd_clust_rec(node, index, thr, &mtr);
 
 		if (err != DB_SUCCESS) {
 

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