List:Commits« Previous MessageNext Message »
From:marko.makela Date:August 15 2011 9:44am
Subject:bzr push into mysql-5.1 branch (marko.makela:3583 to 3584) Bug#11766591
View as plain text  
 3584 Marko Mäkelä	2011-08-15
      Bug #11766591 59733: Possible deadlock when buffered changes are to be
      discarded in buf_page_create()
      
      This bug turned out to be a false alarm, a bug in the UNIV_SYNC_DEBUG
      diagnostic code. Because of this, the patch was not backported to the
      built-in InnoDB in MySQL 5.1. Furthermore, there is no test case for
      InnoDB Plugin in MySQL 5.1, because the delete buffering in MySQL 5.5
      makes triggering the failure much easier.
      
      When a freed page for which there exist orphaned buffered changes is
      allocated and reused for something else, buf_page_create() will discard
      the buffered changes by invoking ibuf_merge_or_delete_for_page().
      This would violate the InnoDB latching order.
      
      Tweak the latching order as follows. Move SYNC_IBUF_MUTEX below
      SYNC_FSP_PAGE, where it logically belongs, and assign new latching
      levels for the ibuf->index->lock and the insert buffer B-tree pages:
      
      #define SYNC_IBUF_MUTEX		370	/* ibuf_mutex */
      #define SYNC_IBUF_INDEX_TREE	360
      #define SYNC_IBUF_TREE_NODE_NEW	359
      #define SYNC_IBUF_TREE_NODE	358
      
      btr_block_get(), btr_page_get(): In UNIV_SYNC_DEBUG, add the parameter
      "index" for determining the appropriate latching order
      (SYNC_IBUF_TREE_NODE or SYNC_TREE_NODE).
      
      btr_page_alloc_for_ibuf(), btr_create(): Use SYNC_IBUF_TREE_NODE_NEW
      instead of SYNC_TREE_NODE_NEW for insert buffer pages.
      
      btr_cur_search_to_nth_level(), btr_pcur_restore_position_func(): Use
      SYNC_IBUF_TREE_NODE instead of SYNC_TREE_NODE for insert buffer pages.
      
      btr_search_guess_on_hash(): Assert that the index is not an insert buffer tree.
      
      dict_index_add_to_cache(): Use SYNC_IBUF_INDEX_TREE for the insert
      buffer tree (ibuf->index->lock).
      
      ibuf0ibuf.c: Use SYNC_IBUF_TREE_NODE or SYNC_IBUF_TREE_NODE_NEW for
      all B-tree pages.
      
      ibuf_merge_or_delete_for_page(): Assert that the user page is
      BUF_IO_READ fixed. Only in this way it is OK to latch it as
      SYNC_IBUF_TREE_NODE instead of the proper SYNC_TREE_NODE (which would
      violate the changed latching order).
      
      sync_thread_add_level(): Remove the special tweak for
      SYNC_IBUF_MUTEX. Add rules for the added latching levels.
      
      rb:591 approved by Jimmy Yang

    modified:
      storage/innodb_plugin/ChangeLog
      storage/innodb_plugin/btr/btr0btr.c
      storage/innodb_plugin/btr/btr0cur.c
      storage/innodb_plugin/btr/btr0pcur.c
      storage/innodb_plugin/btr/btr0sea.c
      storage/innodb_plugin/dict/dict0crea.c
      storage/innodb_plugin/dict/dict0dict.c
      storage/innodb_plugin/ibuf/ibuf0ibuf.c
      storage/innodb_plugin/include/btr0btr.h
      storage/innodb_plugin/include/btr0btr.ic
      storage/innodb_plugin/include/sync0sync.h
      storage/innodb_plugin/sync/sync0sync.c
 3583 Georgi Kodinov	2011-08-12
      bumped the version to 5.1.60

    modified:
      configure.in
=== modified file 'storage/innodb_plugin/ChangeLog'
--- a/storage/innodb_plugin/ChangeLog	revid:georgi.kodinov@oracle.com-20110812112017-1gm7poq32bxql6qq
+++ b/storage/innodb_plugin/ChangeLog	revid:marko.makela@stripped0815091143-h3zbvm0pv8ni3qql
@@ -1,3 +1,12 @@
+2011-08-15	The InnoDB Team
+
+	* btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c,
+	dict/dict0crea.c, dict/dict0dict.c, ibuf/ibuf0ibuf.c,
+	include/btr0btr.h, include/btr0btr.ic, include/sync0sync.h,
+	sync/sync0sync.c:
+	Fix Bug#11766591 59733: Possible deadlock when buffered changes
+	are to be discarded in buf_page_create()
+
 2011-08-08	The InnoDB Team
 
 	* row/row0sel.c:

=== modified file 'storage/innodb_plugin/btr/btr0btr.c'
--- a/storage/innodb_plugin/btr/btr0btr.c	revid:georgi.kodinov@stripped0110812112017-1gm7poq32bxql6qq
+++ b/storage/innodb_plugin/btr/btr0btr.c	revid:marko.makela@stripped143-h3zbvm0pv8ni3qql
@@ -690,7 +690,8 @@ btr_root_block_get(
 	zip_size = dict_table_zip_size(index->table);
 	root_page_no = dict_index_get_page(index);
 
-	block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
+	block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
+			      index, mtr);
 	ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
 	     == dict_table_is_comp(index->table));
 #ifdef UNIV_BTR_DEBUG
@@ -891,7 +892,7 @@ btr_page_alloc_for_ibuf(
 				 dict_table_zip_size(index->table),
 				 node_addr.page, RW_X_LATCH, mtr);
 	new_page = buf_block_get_frame(new_block);
-	buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
+	buf_block_dbg_add_level(new_block, SYNC_IBUF_TREE_NODE_NEW);
 
 	flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 		    new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
@@ -1139,7 +1140,7 @@ btr_node_ptr_get_child(
 	page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
 
 	return(btr_block_get(space, dict_table_zip_size(index->table),
-			     page_no, RW_X_LATCH, mtr));
+			     page_no, RW_X_LATCH, index, mtr));
 }
 
 /************************************************************//**
@@ -1311,7 +1312,8 @@ btr_create(
 			space, 0,
 			IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
 
-		buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW);
+		buf_block_dbg_add_level(
+			ibuf_hdr_block, SYNC_IBUF_TREE_NODE_NEW);
 
 		ut_ad(buf_block_get_page_no(ibuf_hdr_block)
 		      == IBUF_HEADER_PAGE_NO);
@@ -1348,10 +1350,9 @@ btr_create(
 	page_no = buf_block_get_page_no(block);
 	frame = buf_block_get_frame(block);
 
-	buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
-
 	if (type & DICT_IBUF) {
 		/* It is an insert buffer tree: initialize the free list */
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
 
 		ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
 
@@ -1359,6 +1360,8 @@ btr_create(
 	} else {
 		/* It is a non-ibuf tree: create a file segment for leaf
 		pages */
+		buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
+
 		if (!fseg_create(space, page_no,
 				 PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
 			/* Not enough space for new segment, free root
@@ -1430,7 +1433,8 @@ btr_free_but_not_root(
 leaf_loop:
 	mtr_start(&mtr);
 
-	root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
+	root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
+			    NULL, &mtr);
 #ifdef UNIV_BTR_DEBUG
 	ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
 				    + root, space));
@@ -1452,7 +1456,8 @@ leaf_loop:
 top_loop:
 	mtr_start(&mtr);
 
-	root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
+	root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
+			    NULL, &mtr);
 #ifdef UNIV_BTR_DEBUG
 	ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
 				    + root, space));
@@ -1478,13 +1483,13 @@ 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: a mini-transaction which has already
-				been started */
+	mtr_t*	mtr)		/*!< in/out: mini-transaction */
 {
 	buf_block_t*	block;
 	fseg_header_t*	header;
 
-	block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
+	block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
+			      NULL, mtr);
 
 	btr_search_drop_page_hash_index(block);
 
@@ -2362,9 +2367,8 @@ btr_attach_half_pages(
 	/* Update page links of the level */
 
 	if (prev_page_no != FIL_NULL) {
-		buf_block_t*	prev_block = btr_block_get(space, zip_size,
-							   prev_page_no,
-							   RW_X_LATCH, mtr);
+		buf_block_t*	prev_block = btr_block_get(
+			space, zip_size, prev_page_no, RW_X_LATCH, index, mtr);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(page_is_comp(prev_block->frame) == page_is_comp(page));
 		ut_a(btr_page_get_next(prev_block->frame, mtr)
@@ -2377,9 +2381,8 @@ btr_attach_half_pages(
 	}
 
 	if (next_page_no != FIL_NULL) {
-		buf_block_t*	next_block = btr_block_get(space, zip_size,
-							   next_page_no,
-							   RW_X_LATCH, mtr);
+		buf_block_t*	next_block = btr_block_get(
+			space, zip_size, next_page_no, RW_X_LATCH, index, mtr);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(page_is_comp(next_block->frame) == page_is_comp(page));
 		ut_a(btr_page_get_prev(next_block->frame, mtr)
@@ -2801,17 +2804,42 @@ func_exit:
 	return(rec);
 }
 
+#ifdef UNIV_SYNC_DEBUG
+/*************************************************************//**
+Removes a page from the level list of pages.
+@param space	in: space where removed
+@param zip_size	in: compressed page size in bytes, or 0 for uncompressed
+@param page	in/out: page to remove
+@param index	in: index tree
+@param mtr	in/out: mini-transaction */
+# define btr_level_list_remove(space,zip_size,page,index,mtr)		\
+	btr_level_list_remove_func(space,zip_size,page,index,mtr)
+#else /* UNIV_SYNC_DEBUG */
+/*************************************************************//**
+Removes a page from the level list of pages.
+@param space	in: space where removed
+@param zip_size	in: compressed page size in bytes, or 0 for uncompressed
+@param page	in/out: page to remove
+@param index	in: index tree
+@param mtr	in/out: mini-transaction */
+# define btr_level_list_remove(space,zip_size,page,index,mtr)		\
+	btr_level_list_remove_func(space,zip_size,page,mtr)
+#endif /* UNIV_SYNC_DEBUG */
+
 /*************************************************************//**
 Removes a page from the level list of pages. */
-static
+static __attribute__((nonnull))
 void
-btr_level_list_remove(
-/*==================*/
-	ulint		space,	/*!< in: space where removed */
-	ulint		zip_size,/*!< in: compressed page size in bytes
-				or 0 for uncompressed pages */
-	page_t*		page,	/*!< in: page to remove */
-	mtr_t*		mtr)	/*!< in: mtr */
+btr_level_list_remove_func(
+/*=======================*/
+	ulint			space,	/*!< in: space where removed */
+	ulint			zip_size,/*!< in: compressed page size in bytes
+					or 0 for uncompressed pages */
+	page_t*			page,	/*!< in/out: page to remove */
+#ifdef UNIV_SYNC_DEBUG
+	const dict_index_t*	index,	/*!< in: index tree */
+#endif /* UNIV_SYNC_DEBUG */
+	mtr_t*			mtr)	/*!< in/out: mini-transaction */
 {
 	ulint	prev_page_no;
 	ulint	next_page_no;
@@ -2829,7 +2857,7 @@ btr_level_list_remove(
 	if (prev_page_no != FIL_NULL) {
 		buf_block_t*	prev_block
 			= btr_block_get(space, zip_size, prev_page_no,
-					RW_X_LATCH, mtr);
+					RW_X_LATCH, index, mtr);
 		page_t*		prev_page
 			= buf_block_get_frame(prev_block);
 #ifdef UNIV_BTR_DEBUG
@@ -2846,7 +2874,7 @@ btr_level_list_remove(
 	if (next_page_no != FIL_NULL) {
 		buf_block_t*	next_block
 			= btr_block_get(space, zip_size, next_page_no,
-					RW_X_LATCH, mtr);
+					RW_X_LATCH, index, mtr);
 		page_t*		next_page
 			= buf_block_get_frame(next_block);
 #ifdef UNIV_BTR_DEBUG
@@ -3172,7 +3200,7 @@ btr_compress(
 	if (is_left) {
 
 		merge_block = btr_block_get(space, zip_size, left_page_no,
-					    RW_X_LATCH, mtr);
+					    RW_X_LATCH, index, mtr);
 		merge_page = buf_block_get_frame(merge_block);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(btr_page_get_next(merge_page, mtr)
@@ -3181,7 +3209,7 @@ btr_compress(
 	} else if (right_page_no != FIL_NULL) {
 
 		merge_block = btr_block_get(space, zip_size, right_page_no,
-					    RW_X_LATCH, mtr);
+					    RW_X_LATCH, index, mtr);
 		merge_page = buf_block_get_frame(merge_block);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(btr_page_get_prev(merge_page, mtr)
@@ -3270,7 +3298,7 @@ err_exit:
 		btr_search_drop_page_hash_index(block);
 
 		/* Remove the page from the level list */
-		btr_level_list_remove(space, zip_size, page, mtr);
+		btr_level_list_remove(space, zip_size, page, index, mtr);
 
 		btr_node_ptr_delete(index, block, mtr);
 		lock_update_merge_left(merge_block, orig_pred, block);
@@ -3327,7 +3355,7 @@ err_exit:
 #endif /* UNIV_BTR_DEBUG */
 
 		/* Remove the page from the level list */
-		btr_level_list_remove(space, zip_size, page, mtr);
+		btr_level_list_remove(space, zip_size, page, index, mtr);
 
 		/* Replace the address of the old child node (= page) with the
 		address of the merge page to the right */
@@ -3519,7 +3547,7 @@ btr_discard_page(
 
 	if (left_page_no != FIL_NULL) {
 		merge_block = btr_block_get(space, zip_size, left_page_no,
-					    RW_X_LATCH, mtr);
+					    RW_X_LATCH, index, mtr);
 		merge_page = buf_block_get_frame(merge_block);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(btr_page_get_next(merge_page, mtr)
@@ -3527,7 +3555,7 @@ btr_discard_page(
 #endif /* UNIV_BTR_DEBUG */
 	} else if (right_page_no != FIL_NULL) {
 		merge_block = btr_block_get(space, zip_size, right_page_no,
-					    RW_X_LATCH, mtr);
+					    RW_X_LATCH, index, mtr);
 		merge_page = buf_block_get_frame(merge_block);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(btr_page_get_prev(merge_page, mtr)
@@ -3562,7 +3590,7 @@ btr_discard_page(
 	btr_node_ptr_delete(index, block, mtr);
 
 	/* Remove the page from the level list */
-	btr_level_list_remove(space, zip_size, page, mtr);
+	btr_level_list_remove(space, zip_size, page, index, mtr);
 #ifdef UNIV_ZIP_DEBUG
 	{
 		page_zip_des_t*	merge_page_zip
@@ -4080,7 +4108,7 @@ loop:
 	if (right_page_no != FIL_NULL) {
 		const rec_t*	right_rec;
 		right_block = btr_block_get(space, zip_size, right_page_no,
-					    RW_X_LATCH, &mtr);
+					    RW_X_LATCH, index, &mtr);
 		right_page = buf_block_get_frame(right_block);
 		if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
 				  != page_get_page_no(page))) {
@@ -4306,7 +4334,7 @@ node_ptr_fails:
 		mtr_start(&mtr);
 
 		block = btr_block_get(space, zip_size, right_page_no,
-				      RW_X_LATCH, &mtr);
+				      RW_X_LATCH, index, &mtr);
 		page = buf_block_get_frame(block);
 
 		goto loop;

=== modified file 'storage/innodb_plugin/btr/btr0cur.c'
--- a/storage/innodb_plugin/btr/btr0cur.c	revid:georgi.kodinov@stripped
+++ b/storage/innodb_plugin/btr/btr0cur.c	revid:marko.makela@oracle.com-20110815091143-h3zbvm0pv8ni3qql
@@ -238,7 +238,8 @@ btr_cur_latch_leaves(
 	case BTR_SEARCH_LEAF:
 	case BTR_MODIFY_LEAF:
 		mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH;
-		get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
+		get_block = btr_block_get(
+			space, zip_size, page_no, mode, cursor->index, mtr);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
 #endif /* UNIV_BTR_DEBUG */
@@ -249,9 +250,9 @@ btr_cur_latch_leaves(
 		left_page_no = btr_page_get_prev(page, mtr);
 
 		if (left_page_no != FIL_NULL) {
-			get_block = btr_block_get(space, zip_size,
-						  left_page_no,
-						  RW_X_LATCH, mtr);
+			get_block = btr_block_get(
+				space, zip_size, left_page_no,
+				RW_X_LATCH, cursor->index, mtr);
 #ifdef UNIV_BTR_DEBUG
 			ut_a(page_is_comp(get_block->frame)
 			     == page_is_comp(page));
@@ -261,8 +262,9 @@ btr_cur_latch_leaves(
 			get_block->check_index_page_at_flush = TRUE;
 		}
 
-		get_block = btr_block_get(space, zip_size, page_no,
-					  RW_X_LATCH, mtr);
+		get_block = btr_block_get(
+			space, zip_size, page_no,
+			RW_X_LATCH, cursor->index, mtr);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
 #endif /* UNIV_BTR_DEBUG */
@@ -271,9 +273,9 @@ btr_cur_latch_leaves(
 		right_page_no = btr_page_get_next(page, mtr);
 
 		if (right_page_no != FIL_NULL) {
-			get_block = btr_block_get(space, zip_size,
-						  right_page_no,
-						  RW_X_LATCH, mtr);
+			get_block = btr_block_get(
+				space, zip_size, right_page_no,
+				RW_X_LATCH, cursor->index, mtr);
 #ifdef UNIV_BTR_DEBUG
 			ut_a(page_is_comp(get_block->frame)
 			     == page_is_comp(page));
@@ -292,8 +294,9 @@ btr_cur_latch_leaves(
 		left_page_no = btr_page_get_prev(page, mtr);
 
 		if (left_page_no != FIL_NULL) {
-			get_block = btr_block_get(space, zip_size,
-						  left_page_no, mode, mtr);
+			get_block = btr_block_get(
+				space, zip_size,
+				left_page_no, mode, cursor->index, mtr);
 			cursor->left_block = get_block;
 #ifdef UNIV_BTR_DEBUG
 			ut_a(page_is_comp(get_block->frame)
@@ -304,7 +307,8 @@ btr_cur_latch_leaves(
 			get_block->check_index_page_at_flush = TRUE;
 		}
 
-		get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
+		get_block = btr_block_get(
+			space, zip_size, page_no, mode, cursor->index, mtr);
 #ifdef UNIV_BTR_DEBUG
 		ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
 #endif /* UNIV_BTR_DEBUG */
@@ -572,7 +576,9 @@ retry_page_get:
 			ut_a(!page_zip || page_zip_validate(page_zip, page));
 #endif /* UNIV_ZIP_DEBUG */
 
-			buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+			buf_block_dbg_add_level(
+				block, dict_index_is_ibuf(index)
+				? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
 		}
 
 		ut_ad(0 == ut_dulint_cmp(index->id,
@@ -630,8 +636,8 @@ retry_page_get:
 
 			if (level > 0) {
 				/* x-latch the page */
-				page = btr_page_get(space, zip_size,
-						    page_no, RW_X_LATCH, mtr);
+				page = btr_page_get(space, zip_size, page_no,
+						    RW_X_LATCH, index, mtr);
 				ut_a((ibool)!!page_is_comp(page)
 				     == dict_table_is_comp(index->table));
 			}

=== modified file 'storage/innodb_plugin/btr/btr0pcur.c'
--- a/storage/innodb_plugin/btr/btr0pcur.c	revid:georgi.kodinov@stripped2017-1gm7poq32bxql6qq
+++ b/storage/innodb_plugin/btr/btr0pcur.c	revid:marko.makela@strippedvm0pv8ni3qql
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, 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
@@ -266,8 +266,10 @@ btr_pcur_restore_position_func(
 					file, line, mtr))) {
 			cursor->pos_state = BTR_PCUR_IS_POSITIONED;
 
-			buf_block_dbg_add_level(btr_pcur_get_block(cursor),
-						SYNC_TREE_NODE);
+			buf_block_dbg_add_level(
+				btr_pcur_get_block(cursor),
+				dict_index_is_ibuf(index)
+				? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
 
 			if (cursor->rel_pos == BTR_PCUR_ON) {
 #ifdef UNIV_DEBUG
@@ -417,7 +419,8 @@ btr_pcur_move_to_next_page(
 	ut_ad(next_page_no != FIL_NULL);
 
 	next_block = btr_block_get(space, zip_size, next_page_no,
-				   cursor->latch_mode, mtr);
+				   cursor->latch_mode,
+				   btr_pcur_get_btr_cur(cursor)->index, mtr);
 	next_page = buf_block_get_frame(next_block);
 #ifdef UNIV_BTR_DEBUG
 	ut_a(page_is_comp(next_page) == page_is_comp(page));

=== modified file 'storage/innodb_plugin/btr/btr0sea.c'
--- a/storage/innodb_plugin/btr/btr0sea.c	revid:georgi.kodinov@stripped
+++ b/storage/innodb_plugin/btr/btr0sea.c	revid:marko.makela@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2008, Google Inc.
 
 Portions of this file contain modifications contributed and copyrighted by
@@ -832,6 +832,7 @@ btr_search_guess_on_hash(
 	btr_pcur_t	pcur;
 #endif
 	ut_ad(index && info && tuple && cursor && mtr);
+	ut_ad(!dict_index_is_ibuf(index));
 	ut_ad((latch_mode == BTR_SEARCH_LEAF)
 	      || (latch_mode == BTR_MODIFY_LEAF));
 

=== modified file 'storage/innodb_plugin/dict/dict0crea.c'
--- a/storage/innodb_plugin/dict/dict0crea.c	revid:georgi.kodinov@strippedpoq32bxql6qq
+++ b/storage/innodb_plugin/dict/dict0crea.c	revid:marko.makela@strippedi3qql
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, 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
@@ -828,7 +828,7 @@ dict_truncate_index_tree(
 	appropriate field in the SYS_INDEXES record: this mini-transaction
 	marks the B-tree totally truncated */
 
-	btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
+	btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, NULL, mtr);
 
 	btr_free_root(space, zip_size, root_page_no, mtr);
 create:

=== modified file 'storage/innodb_plugin/dict/dict0dict.c'
--- a/storage/innodb_plugin/dict/dict0dict.c	revid:georgi.kodinov@stripped1gm7poq32bxql6qq
+++ b/storage/innodb_plugin/dict/dict0dict.c	revid:marko.makela@strippedpv8ni3qql
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, 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
@@ -1661,7 +1661,9 @@ undo_size_ok:
 	new_index->stat_n_leaf_pages = 1;
 
 	new_index->page = page_no;
-	rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
+	rw_lock_create(&new_index->lock,
+		       dict_index_is_ibuf(index)
+		       ? SYNC_IBUF_INDEX_TREE : SYNC_INDEX_TREE);
 
 	if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
 

=== modified file 'storage/innodb_plugin/ibuf/ibuf0ibuf.c'
--- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c	revid:georgi.kodinov@strippedql6qq
+++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c	revid:marko.makela@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1997, 2011, 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
@@ -356,7 +356,7 @@ ibuf_tree_root_get(
 	block = buf_page_get(
 		IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr);
 
-	buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+	buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
 
 	return(buf_block_get_frame(block));
 }
@@ -496,7 +496,7 @@ ibuf_init_at_db_start(void)
 		block = buf_page_get(
 			IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO,
 			RW_X_LATCH, &mtr);
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
 
 		root = buf_block_get_frame(block);
 	}
@@ -1766,7 +1766,7 @@ ibuf_add_free_page(void)
 		block = buf_page_get(
 			IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
 
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
 
 
 		page = buf_block_get_frame(block);
@@ -1897,8 +1897,7 @@ ibuf_remove_free_page(void)
 		block = buf_page_get(
 			IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
 
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE);
-
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
 
 		page = buf_block_get_frame(block);
 	}
@@ -2408,7 +2407,7 @@ ibuf_get_volume_buffered(
 		block = buf_page_get(
 			IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr);
 
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
 
 
 		prev_page = buf_block_get_frame(block);
@@ -2482,7 +2481,7 @@ count_later:
 		block = buf_page_get(
 			IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr);
 
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
 
 
 		next_page = buf_block_get_frame(block);
@@ -3248,6 +3247,7 @@ ibuf_merge_or_delete_for_page(
 	ut_ad(!block || buf_block_get_space(block) == space);
 	ut_ad(!block || buf_block_get_page_no(block) == page_no);
 	ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
+	ut_ad(!block || buf_block_get_io_fix(block) == BUF_IO_READ);
 
 	if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE
 	    || trx_sys_hdr_page(space, page_no)) {
@@ -3403,7 +3403,13 @@ loop:
 
 		ut_a(success);
 
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+		/* This is a user page (secondary index leaf page),
+		but we pretend that it is a change buffer page in
+		order to obey the latching order. This should be OK,
+		because buffered changes are applied immediately while
+		the block is io-fixed. Other threads must not try to
+		latch an io-fixed block. */
+		buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
 	}
 
 	/* Position pcur in the insert buffer at the first entry for this

=== modified file 'storage/innodb_plugin/include/btr0btr.h'
--- a/storage/innodb_plugin/include/btr0btr.h	revid:georgi.kodinov@stripped
+++ b/storage/innodb_plugin/include/btr0btr.h	revid:marko.makela@stripped
@@ -188,26 +188,45 @@ btr_block_get_func(
 	ulint		mode,		/*!< in: latch mode */
 	const char*	file,		/*!< in: file name */
 	ulint		line,		/*!< in: line where called */
-	mtr_t*		mtr)		/*!< in/out: mtr */
-	__attribute__((nonnull));
+# ifdef UNIV_SYNC_DEBUG
+	const dict_index_t*	index,	/*!< in: index tree, may be NULL
+					if it is not an insert buffer tree */
+# endif /* UNIV_SYNC_DEBUG */
+	mtr_t*		mtr);		/*!< in/out: mini-transaction */
+# ifdef UNIV_SYNC_DEBUG
 /** Gets a buffer page and declares its latching order level.
 @param space	tablespace identifier
 @param zip_size	compressed page size in bytes or 0 for uncompressed pages
 @param page_no	page number
 @param mode	latch mode
+@param index	index tree, may be NULL if not the insert buffer tree
 @param mtr	mini-transaction handle
 @return the block descriptor */
-# define btr_block_get(space,zip_size,page_no,mode,mtr) \
+#  define btr_block_get(space,zip_size,page_no,mode,index,mtr)	\
+	btr_block_get_func(space,zip_size,page_no,mode,		\
+			   __FILE__,__LINE__,index,mtr)
+# else /* UNIV_SYNC_DEBUG */
+/** Gets a buffer page and declares its latching order level.
+@param space	tablespace identifier
+@param zip_size	compressed page size in bytes or 0 for uncompressed pages
+@param page_no	page number
+@param mode	latch mode
+@param idx	index tree, may be NULL if not the insert buffer tree
+@param mtr	mini-transaction handle
+@return the block descriptor */
+#  define btr_block_get(space,zip_size,page_no,mode,idx,mtr)		\
 	btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr)
+# endif /* UNIV_SYNC_DEBUG */
 /** Gets a buffer page and declares its latching order level.
 @param space	tablespace identifier
 @param zip_size	compressed page size in bytes or 0 for uncompressed pages
 @param page_no	page number
 @param mode	latch mode
+@param idx	index tree, may be NULL if not the insert buffer tree
 @param mtr	mini-transaction handle
 @return the uncompressed page frame */
-# define btr_page_get(space,zip_size,page_no,mode,mtr) \
-	buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,mtr))
+# define btr_page_get(space,zip_size,page_no,mode,idx,mtr)		\
+	buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,idx,mtr))
 #endif /* !UNIV_HOTBACKUP */
 /**************************************************************//**
 Gets the index id field of a page.
@@ -333,8 +352,7 @@ 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: a mini-transaction which has already
-				been started */
+	mtr_t*	mtr);		/*!< in/out: mini-transaction */
 /*************************************************************//**
 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.

=== modified file 'storage/innodb_plugin/include/btr0btr.ic'
--- a/storage/innodb_plugin/include/btr0btr.ic	revid:georgi.kodinov@stripped-20110812112017-1gm7poq32bxql6qq
+++ b/storage/innodb_plugin/include/btr0btr.ic	revid:marko.makela@stripped0815091143-h3zbvm0pv8ni3qql
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2011, 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
@@ -48,6 +48,10 @@ btr_block_get_func(
 	ulint		mode,		/*!< in: latch mode */
 	const char*	file,		/*!< in: file name */
 	ulint		line,		/*!< in: line where called */
+#ifdef UNIV_SYNC_DEBUG
+	const dict_index_t*	index,	/*!< in: index tree, may be NULL
+					if it is not an insert buffer tree */
+#endif /* UNIV_SYNC_DEBUG */
 	mtr_t*		mtr)		/*!< in/out: mtr */
 {
 	buf_block_t*	block;
@@ -57,7 +61,9 @@ btr_block_get_func(
 
 	if (mode != RW_NO_LATCH) {
 
-		buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+		buf_block_dbg_add_level(
+			block, index != NULL && dict_index_is_ibuf(index)
+			? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
 	}
 
 	return(block);

=== modified file 'storage/innodb_plugin/include/sync0sync.h'
--- a/storage/innodb_plugin/include/sync0sync.h	revid:georgi.kodinov@strippedql6qq
+++ b/storage/innodb_plugin/include/sync0sync.h	revid:marko.makela@strippedl
@@ -448,10 +448,6 @@ or row lock! */
 #define SYNC_DICT_HEADER	995
 #define SYNC_IBUF_HEADER	914
 #define SYNC_IBUF_PESS_INSERT_MUTEX 912
-#define SYNC_IBUF_MUTEX		910	/* ibuf mutex is really below
-					SYNC_FSP_PAGE: we assign a value this
-					high only to make the program to pass
-					the debug checks */
 /*-------------------------------*/
 #define	SYNC_INDEX_TREE		900
 #define SYNC_TREE_NODE_NEW	892
@@ -468,8 +464,11 @@ or row lock! */
 #define	SYNC_FSP		400
 #define	SYNC_FSP_PAGE		395
 /*------------------------------------- Insert buffer headers */
-/*------------------------------------- ibuf_mutex */
+#define SYNC_IBUF_MUTEX		370	/* ibuf_mutex */
 /*------------------------------------- Insert buffer tree */
+#define SYNC_IBUF_INDEX_TREE	360
+#define SYNC_IBUF_TREE_NODE_NEW	359
+#define SYNC_IBUF_TREE_NODE	358
 #define	SYNC_IBUF_BITMAP_MUTEX	351
 #define	SYNC_IBUF_BITMAP	350
 /*------------------------------------- MySQL query cache mutex */

=== modified file 'storage/innodb_plugin/sync/sync0sync.c'
--- a/storage/innodb_plugin/sync/sync0sync.c	revid:georgi.kodinov@stripped
+++ b/storage/innodb_plugin/sync/sync0sync.c	revid:marko.makela@stripped
@@ -1173,6 +1173,7 @@ sync_thread_add_level(
 	case SYNC_DICT_HEADER:
 	case SYNC_TRX_I_S_RWLOCK:
 	case SYNC_TRX_I_S_LAST_READ:
+	case SYNC_IBUF_MUTEX:
 		if (!sync_thread_levels_g(array, level, TRUE)) {
 			fprintf(stderr,
 				"InnoDB: sync_thread_levels_g(array, %lu)"
@@ -1236,22 +1237,28 @@ sync_thread_add_level(
 		     || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE));
 		break;
 	case SYNC_TREE_NODE_NEW:
-		ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)
-		     || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
+		ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE));
 		break;
 	case SYNC_INDEX_TREE:
-		if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)
-		    && sync_thread_levels_contain(array, SYNC_FSP)) {
-			ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1,
-						  TRUE));
+		ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE));
+		break;
+	case SYNC_IBUF_TREE_NODE:
+		ut_a(sync_thread_levels_contain(array, SYNC_IBUF_INDEX_TREE)
+		     || sync_thread_levels_g(array, SYNC_IBUF_TREE_NODE - 1,
+					     TRUE));
+		break;
+	case SYNC_IBUF_TREE_NODE_NEW:
+		ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
+		break;
+	case SYNC_IBUF_INDEX_TREE:
+		if (sync_thread_levels_contain(array, SYNC_FSP)) {
+			ut_a(sync_thread_levels_g(
+				     array, SYNC_FSP_PAGE - 1, TRUE));
 		} else {
-			ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1,
-						  TRUE));
+			ut_a(sync_thread_levels_g(
+				     array, SYNC_IBUF_TREE_NODE - 1, TRUE));
 		}
 		break;
-	case SYNC_IBUF_MUTEX:
-		ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE));
-		break;
 	case SYNC_IBUF_PESS_INSERT_MUTEX:
 		ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE));
 		ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.1 branch (marko.makela:3583 to 3584) Bug#11766591marko.makela16 Aug