Commit d5c36400 authored by Marko Mäkelä's avatar Marko Mäkelä

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
parent 6046cb7b
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 2011-08-08 The InnoDB Team
* row/row0sel.c: * row/row0sel.c:
......
...@@ -690,7 +690,8 @@ btr_root_block_get( ...@@ -690,7 +690,8 @@ btr_root_block_get(
zip_size = dict_table_zip_size(index->table); zip_size = dict_table_zip_size(index->table);
root_page_no = dict_index_get_page(index); 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)) ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
== dict_table_is_comp(index->table)); == dict_table_is_comp(index->table));
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
...@@ -891,7 +892,7 @@ btr_page_alloc_for_ibuf( ...@@ -891,7 +892,7 @@ btr_page_alloc_for_ibuf(
dict_table_zip_size(index->table), dict_table_zip_size(index->table),
node_addr.page, RW_X_LATCH, mtr); node_addr.page, RW_X_LATCH, mtr);
new_page = buf_block_get_frame(new_block); 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, flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
...@@ -1139,7 +1140,7 @@ btr_node_ptr_get_child( ...@@ -1139,7 +1140,7 @@ btr_node_ptr_get_child(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
return(btr_block_get(space, dict_table_zip_size(index->table), 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( ...@@ -1311,7 +1312,8 @@ btr_create(
space, 0, space, 0,
IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); 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) ut_ad(buf_block_get_page_no(ibuf_hdr_block)
== IBUF_HEADER_PAGE_NO); == IBUF_HEADER_PAGE_NO);
...@@ -1348,10 +1350,9 @@ btr_create( ...@@ -1348,10 +1350,9 @@ btr_create(
page_no = buf_block_get_page_no(block); page_no = buf_block_get_page_no(block);
frame = buf_block_get_frame(block); frame = buf_block_get_frame(block);
buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
if (type & DICT_IBUF) { if (type & DICT_IBUF) {
/* It is an insert buffer tree: initialize the free list */ /* 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); ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
...@@ -1359,6 +1360,8 @@ btr_create( ...@@ -1359,6 +1360,8 @@ btr_create(
} else { } else {
/* It is a non-ibuf tree: create a file segment for leaf /* It is a non-ibuf tree: create a file segment for leaf
pages */ pages */
buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
if (!fseg_create(space, page_no, if (!fseg_create(space, page_no,
PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
/* Not enough space for new segment, free root /* Not enough space for new segment, free root
...@@ -1430,7 +1433,8 @@ btr_free_but_not_root( ...@@ -1430,7 +1433,8 @@ btr_free_but_not_root(
leaf_loop: leaf_loop:
mtr_start(&mtr); 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 #ifdef UNIV_BTR_DEBUG
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ root, space)); + root, space));
...@@ -1452,7 +1456,8 @@ leaf_loop: ...@@ -1452,7 +1456,8 @@ leaf_loop:
top_loop: top_loop:
mtr_start(&mtr); 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 #ifdef UNIV_BTR_DEBUG
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ root, space)); + root, space));
...@@ -1478,13 +1483,13 @@ btr_free_root( ...@@ -1478,13 +1483,13 @@ btr_free_root(
ulint zip_size, /*!< in: compressed page size in bytes ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */ or 0 for uncompressed pages */
ulint root_page_no, /*!< in: root page number */ ulint root_page_no, /*!< in: root page number */
mtr_t* mtr) /*!< in: a mini-transaction which has already mtr_t* mtr) /*!< in/out: mini-transaction */
been started */
{ {
buf_block_t* block; buf_block_t* block;
fseg_header_t* header; 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); btr_search_drop_page_hash_index(block);
...@@ -2362,9 +2367,8 @@ btr_attach_half_pages( ...@@ -2362,9 +2367,8 @@ btr_attach_half_pages(
/* Update page links of the level */ /* Update page links of the level */
if (prev_page_no != FIL_NULL) { if (prev_page_no != FIL_NULL) {
buf_block_t* prev_block = btr_block_get(space, zip_size, buf_block_t* prev_block = btr_block_get(
prev_page_no, space, zip_size, prev_page_no, RW_X_LATCH, index, mtr);
RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(prev_block->frame) == page_is_comp(page)); ut_a(page_is_comp(prev_block->frame) == page_is_comp(page));
ut_a(btr_page_get_next(prev_block->frame, mtr) ut_a(btr_page_get_next(prev_block->frame, mtr)
...@@ -2377,9 +2381,8 @@ btr_attach_half_pages( ...@@ -2377,9 +2381,8 @@ btr_attach_half_pages(
} }
if (next_page_no != FIL_NULL) { if (next_page_no != FIL_NULL) {
buf_block_t* next_block = btr_block_get(space, zip_size, buf_block_t* next_block = btr_block_get(
next_page_no, space, zip_size, next_page_no, RW_X_LATCH, index, mtr);
RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(next_block->frame) == page_is_comp(page)); ut_a(page_is_comp(next_block->frame) == page_is_comp(page));
ut_a(btr_page_get_prev(next_block->frame, mtr) ut_a(btr_page_get_prev(next_block->frame, mtr)
...@@ -2801,17 +2804,42 @@ func_exit: ...@@ -2801,17 +2804,42 @@ func_exit:
return(rec); 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. */ Removes a page from the level list of pages. */
static static __attribute__((nonnull))
void void
btr_level_list_remove( btr_level_list_remove_func(
/*==================*/ /*=======================*/
ulint space, /*!< in: space where removed */ ulint space, /*!< in: space where removed */
ulint zip_size,/*!< in: compressed page size in bytes ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */ or 0 for uncompressed pages */
page_t* page, /*!< in: page to remove */ page_t* page, /*!< in/out: page to remove */
mtr_t* mtr) /*!< in: mtr */ #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 prev_page_no;
ulint next_page_no; ulint next_page_no;
...@@ -2829,7 +2857,7 @@ btr_level_list_remove( ...@@ -2829,7 +2857,7 @@ btr_level_list_remove(
if (prev_page_no != FIL_NULL) { if (prev_page_no != FIL_NULL) {
buf_block_t* prev_block buf_block_t* prev_block
= btr_block_get(space, zip_size, prev_page_no, = btr_block_get(space, zip_size, prev_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, index, mtr);
page_t* prev_page page_t* prev_page
= buf_block_get_frame(prev_block); = buf_block_get_frame(prev_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
...@@ -2846,7 +2874,7 @@ btr_level_list_remove( ...@@ -2846,7 +2874,7 @@ btr_level_list_remove(
if (next_page_no != FIL_NULL) { if (next_page_no != FIL_NULL) {
buf_block_t* next_block buf_block_t* next_block
= btr_block_get(space, zip_size, next_page_no, = btr_block_get(space, zip_size, next_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, index, mtr);
page_t* next_page page_t* next_page
= buf_block_get_frame(next_block); = buf_block_get_frame(next_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
...@@ -3172,7 +3200,7 @@ btr_compress( ...@@ -3172,7 +3200,7 @@ btr_compress(
if (is_left) { if (is_left) {
merge_block = btr_block_get(space, zip_size, left_page_no, 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); merge_page = buf_block_get_frame(merge_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(merge_page, mtr) ut_a(btr_page_get_next(merge_page, mtr)
...@@ -3181,7 +3209,7 @@ btr_compress( ...@@ -3181,7 +3209,7 @@ btr_compress(
} else if (right_page_no != FIL_NULL) { } else if (right_page_no != FIL_NULL) {
merge_block = btr_block_get(space, zip_size, right_page_no, 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); merge_page = buf_block_get_frame(merge_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(merge_page, mtr) ut_a(btr_page_get_prev(merge_page, mtr)
...@@ -3270,7 +3298,7 @@ err_exit: ...@@ -3270,7 +3298,7 @@ err_exit:
btr_search_drop_page_hash_index(block); btr_search_drop_page_hash_index(block);
/* Remove the page from the level list */ /* 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); btr_node_ptr_delete(index, block, mtr);
lock_update_merge_left(merge_block, orig_pred, block); lock_update_merge_left(merge_block, orig_pred, block);
...@@ -3327,7 +3355,7 @@ err_exit: ...@@ -3327,7 +3355,7 @@ err_exit:
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
/* Remove the page from the level list */ /* 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 /* Replace the address of the old child node (= page) with the
address of the merge page to the right */ address of the merge page to the right */
...@@ -3519,7 +3547,7 @@ btr_discard_page( ...@@ -3519,7 +3547,7 @@ btr_discard_page(
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
merge_block = btr_block_get(space, zip_size, left_page_no, 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); merge_page = buf_block_get_frame(merge_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(merge_page, mtr) ut_a(btr_page_get_next(merge_page, mtr)
...@@ -3527,7 +3555,7 @@ btr_discard_page( ...@@ -3527,7 +3555,7 @@ btr_discard_page(
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
} else if (right_page_no != FIL_NULL) { } else if (right_page_no != FIL_NULL) {
merge_block = btr_block_get(space, zip_size, right_page_no, 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); merge_page = buf_block_get_frame(merge_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(merge_page, mtr) ut_a(btr_page_get_prev(merge_page, mtr)
...@@ -3562,7 +3590,7 @@ btr_discard_page( ...@@ -3562,7 +3590,7 @@ btr_discard_page(
btr_node_ptr_delete(index, block, mtr); btr_node_ptr_delete(index, block, mtr);
/* Remove the page from the level list */ /* 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 #ifdef UNIV_ZIP_DEBUG
{ {
page_zip_des_t* merge_page_zip page_zip_des_t* merge_page_zip
...@@ -4080,7 +4108,7 @@ loop: ...@@ -4080,7 +4108,7 @@ loop:
if (right_page_no != FIL_NULL) { if (right_page_no != FIL_NULL) {
const rec_t* right_rec; const rec_t* right_rec;
right_block = btr_block_get(space, zip_size, right_page_no, 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); right_page = buf_block_get_frame(right_block);
if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr) if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
!= page_get_page_no(page))) { != page_get_page_no(page))) {
...@@ -4306,7 +4334,7 @@ node_ptr_fails: ...@@ -4306,7 +4334,7 @@ node_ptr_fails:
mtr_start(&mtr); mtr_start(&mtr);
block = btr_block_get(space, zip_size, right_page_no, 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); page = buf_block_get_frame(block);
goto loop; goto loop;
......
...@@ -238,7 +238,8 @@ btr_cur_latch_leaves( ...@@ -238,7 +238,8 @@ btr_cur_latch_leaves(
case BTR_SEARCH_LEAF: case BTR_SEARCH_LEAF:
case BTR_MODIFY_LEAF: case BTR_MODIFY_LEAF:
mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH; 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 #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
...@@ -249,9 +250,9 @@ btr_cur_latch_leaves( ...@@ -249,9 +250,9 @@ btr_cur_latch_leaves(
left_page_no = btr_page_get_prev(page, mtr); left_page_no = btr_page_get_prev(page, mtr);
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
get_block = btr_block_get(space, zip_size, get_block = btr_block_get(
left_page_no, space, zip_size, left_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, cursor->index, mtr);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) ut_a(page_is_comp(get_block->frame)
== page_is_comp(page)); == page_is_comp(page));
...@@ -261,8 +262,9 @@ btr_cur_latch_leaves( ...@@ -261,8 +262,9 @@ btr_cur_latch_leaves(
get_block->check_index_page_at_flush = TRUE; get_block->check_index_page_at_flush = TRUE;
} }
get_block = btr_block_get(space, zip_size, page_no, get_block = btr_block_get(
RW_X_LATCH, mtr); space, zip_size, page_no,
RW_X_LATCH, cursor->index, mtr);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
...@@ -271,9 +273,9 @@ btr_cur_latch_leaves( ...@@ -271,9 +273,9 @@ btr_cur_latch_leaves(
right_page_no = btr_page_get_next(page, mtr); right_page_no = btr_page_get_next(page, mtr);
if (right_page_no != FIL_NULL) { if (right_page_no != FIL_NULL) {
get_block = btr_block_get(space, zip_size, get_block = btr_block_get(
right_page_no, space, zip_size, right_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, cursor->index, mtr);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) ut_a(page_is_comp(get_block->frame)
== page_is_comp(page)); == page_is_comp(page));
...@@ -292,8 +294,9 @@ btr_cur_latch_leaves( ...@@ -292,8 +294,9 @@ btr_cur_latch_leaves(
left_page_no = btr_page_get_prev(page, mtr); left_page_no = btr_page_get_prev(page, mtr);
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
get_block = btr_block_get(space, zip_size, get_block = btr_block_get(
left_page_no, mode, mtr); space, zip_size,
left_page_no, mode, cursor->index, mtr);
cursor->left_block = get_block; cursor->left_block = get_block;
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) ut_a(page_is_comp(get_block->frame)
...@@ -304,7 +307,8 @@ btr_cur_latch_leaves( ...@@ -304,7 +307,8 @@ btr_cur_latch_leaves(
get_block->check_index_page_at_flush = TRUE; 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 #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
...@@ -572,7 +576,9 @@ retry_page_get: ...@@ -572,7 +576,9 @@ retry_page_get:
ut_a(!page_zip || page_zip_validate(page_zip, page)); ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */ #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, ut_ad(0 == ut_dulint_cmp(index->id,
...@@ -630,8 +636,8 @@ retry_page_get: ...@@ -630,8 +636,8 @@ retry_page_get:
if (level > 0) { if (level > 0) {
/* x-latch the page */ /* x-latch the page */
page = btr_page_get(space, zip_size, page = btr_page_get(space, zip_size, page_no,
page_no, RW_X_LATCH, mtr); RW_X_LATCH, index, mtr);
ut_a((ibool)!!page_is_comp(page) ut_a((ibool)!!page_is_comp(page)
== dict_table_is_comp(index->table)); == dict_table_is_comp(index->table));
} }
......
/***************************************************************************** /*****************************************************************************
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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -266,8 +266,10 @@ btr_pcur_restore_position_func( ...@@ -266,8 +266,10 @@ btr_pcur_restore_position_func(
file, line, mtr))) { file, line, mtr))) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->pos_state = BTR_PCUR_IS_POSITIONED;
buf_block_dbg_add_level(btr_pcur_get_block(cursor), buf_block_dbg_add_level(
SYNC_TREE_NODE); btr_pcur_get_block(cursor),
dict_index_is_ibuf(index)
? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
if (cursor->rel_pos == BTR_PCUR_ON) { if (cursor->rel_pos == BTR_PCUR_ON) {
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
...@@ -417,7 +419,8 @@ btr_pcur_move_to_next_page( ...@@ -417,7 +419,8 @@ btr_pcur_move_to_next_page(
ut_ad(next_page_no != FIL_NULL); ut_ad(next_page_no != FIL_NULL);
next_block = btr_block_get(space, zip_size, next_page_no, 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); next_page = buf_block_get_frame(next_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(next_page) == page_is_comp(page)); ut_a(page_is_comp(next_page) == page_is_comp(page));
......
/***************************************************************************** /*****************************************************************************
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. Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by Portions of this file contain modifications contributed and copyrighted by
...@@ -832,6 +832,7 @@ btr_search_guess_on_hash( ...@@ -832,6 +832,7 @@ btr_search_guess_on_hash(
btr_pcur_t pcur; btr_pcur_t pcur;
#endif #endif
ut_ad(index && info && tuple && cursor && mtr); ut_ad(index && info && tuple && cursor && mtr);
ut_ad(!dict_index_is_ibuf(index));
ut_ad((latch_mode == BTR_SEARCH_LEAF) ut_ad((latch_mode == BTR_SEARCH_LEAF)
|| (latch_mode == BTR_MODIFY_LEAF)); || (latch_mode == BTR_MODIFY_LEAF));
......
/***************************************************************************** /*****************************************************************************
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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -828,7 +828,7 @@ dict_truncate_index_tree( ...@@ -828,7 +828,7 @@ dict_truncate_index_tree(
appropriate field in the SYS_INDEXES record: this mini-transaction appropriate field in the SYS_INDEXES record: this mini-transaction
marks the B-tree totally truncated */ 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); btr_free_root(space, zip_size, root_page_no, mtr);
create: create:
......
/***************************************************************************** /*****************************************************************************
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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -1661,7 +1661,9 @@ undo_size_ok: ...@@ -1661,7 +1661,9 @@ undo_size_ok:
new_index->stat_n_leaf_pages = 1; new_index->stat_n_leaf_pages = 1;
new_index->page = page_no; 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)) { if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
......
/***************************************************************************** /*****************************************************************************
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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -356,7 +356,7 @@ ibuf_tree_root_get( ...@@ -356,7 +356,7 @@ ibuf_tree_root_get(
block = buf_page_get( block = buf_page_get(
IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr); 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)); return(buf_block_get_frame(block));
} }
...@@ -496,7 +496,7 @@ ibuf_init_at_db_start(void) ...@@ -496,7 +496,7 @@ ibuf_init_at_db_start(void)
block = buf_page_get( block = buf_page_get(
IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO,
RW_X_LATCH, &mtr); 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); root = buf_block_get_frame(block);
} }
...@@ -1766,7 +1766,7 @@ ibuf_add_free_page(void) ...@@ -1766,7 +1766,7 @@ ibuf_add_free_page(void)
block = buf_page_get( block = buf_page_get(
IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); 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); page = buf_block_get_frame(block);
...@@ -1897,8 +1897,7 @@ ibuf_remove_free_page(void) ...@@ -1897,8 +1897,7 @@ ibuf_remove_free_page(void)
block = buf_page_get( block = buf_page_get(
IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); 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); page = buf_block_get_frame(block);
} }
...@@ -2408,7 +2407,7 @@ ibuf_get_volume_buffered( ...@@ -2408,7 +2407,7 @@ ibuf_get_volume_buffered(
block = buf_page_get( block = buf_page_get(
IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr); 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); prev_page = buf_block_get_frame(block);
...@@ -2482,7 +2481,7 @@ count_later: ...@@ -2482,7 +2481,7 @@ count_later:
block = buf_page_get( block = buf_page_get(
IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr); 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); next_page = buf_block_get_frame(block);
...@@ -3248,6 +3247,7 @@ ibuf_merge_or_delete_for_page( ...@@ -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_space(block) == space);
ut_ad(!block || buf_block_get_page_no(block) == page_no); 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_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 if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE
|| trx_sys_hdr_page(space, page_no)) { || trx_sys_hdr_page(space, page_no)) {
...@@ -3403,7 +3403,13 @@ loop: ...@@ -3403,7 +3403,13 @@ loop:
ut_a(success); 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 /* Position pcur in the insert buffer at the first entry for this
......
...@@ -188,26 +188,45 @@ btr_block_get_func( ...@@ -188,26 +188,45 @@ btr_block_get_func(
ulint mode, /*!< in: latch mode */ ulint mode, /*!< in: latch mode */
const char* file, /*!< in: file name */ const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */ ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in/out: mtr */ # ifdef UNIV_SYNC_DEBUG
__attribute__((nonnull)); 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,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. /** Gets a buffer page and declares its latching order level.
@param space tablespace identifier @param space tablespace identifier
@param zip_size compressed page size in bytes or 0 for uncompressed pages @param zip_size compressed page size in bytes or 0 for uncompressed pages
@param page_no page number @param page_no page number
@param mode latch mode @param mode latch mode
@param idx index tree, may be NULL if not the insert buffer tree
@param mtr mini-transaction handle @param mtr mini-transaction handle
@return the block descriptor */ @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,idx,mtr) \
btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,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. /** Gets a buffer page and declares its latching order level.
@param space tablespace identifier @param space tablespace identifier
@param zip_size compressed page size in bytes or 0 for uncompressed pages @param zip_size compressed page size in bytes or 0 for uncompressed pages
@param page_no page number @param page_no page number
@param mode latch mode @param mode latch mode
@param idx index tree, may be NULL if not the insert buffer tree
@param mtr mini-transaction handle @param mtr mini-transaction handle
@return the uncompressed page frame */ @return the uncompressed page frame */
# define btr_page_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,mtr)) buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,idx,mtr))
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
/**************************************************************//** /**************************************************************//**
Gets the index id field of a page. Gets the index id field of a page.
...@@ -333,8 +352,7 @@ btr_free_root( ...@@ -333,8 +352,7 @@ btr_free_root(
ulint zip_size, /*!< in: compressed page size in bytes ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */ or 0 for uncompressed pages */
ulint root_page_no, /*!< in: root page number */ ulint root_page_no, /*!< in: root page number */
mtr_t* mtr); /*!< in: a mini-transaction which has already mtr_t* mtr); /*!< in/out: mini-transaction */
been started */
/*************************************************************//** /*************************************************************//**
Makes tree one level higher by splitting the root, and inserts 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. the tuple. It is assumed that mtr contains an x-latch on the tree.
......
/***************************************************************************** /*****************************************************************************
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 This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -48,6 +48,10 @@ btr_block_get_func( ...@@ -48,6 +48,10 @@ btr_block_get_func(
ulint mode, /*!< in: latch mode */ ulint mode, /*!< in: latch mode */
const char* file, /*!< in: file name */ const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */ 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 */ mtr_t* mtr) /*!< in/out: mtr */
{ {
buf_block_t* block; buf_block_t* block;
...@@ -57,7 +61,9 @@ btr_block_get_func( ...@@ -57,7 +61,9 @@ btr_block_get_func(
if (mode != RW_NO_LATCH) { 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); return(block);
......
...@@ -448,10 +448,6 @@ or row lock! */ ...@@ -448,10 +448,6 @@ or row lock! */
#define SYNC_DICT_HEADER 995 #define SYNC_DICT_HEADER 995
#define SYNC_IBUF_HEADER 914 #define SYNC_IBUF_HEADER 914
#define SYNC_IBUF_PESS_INSERT_MUTEX 912 #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_INDEX_TREE 900
#define SYNC_TREE_NODE_NEW 892 #define SYNC_TREE_NODE_NEW 892
...@@ -468,8 +464,11 @@ or row lock! */ ...@@ -468,8 +464,11 @@ or row lock! */
#define SYNC_FSP 400 #define SYNC_FSP 400
#define SYNC_FSP_PAGE 395 #define SYNC_FSP_PAGE 395
/*------------------------------------- Insert buffer headers */ /*------------------------------------- Insert buffer headers */
/*------------------------------------- ibuf_mutex */ #define SYNC_IBUF_MUTEX 370 /* ibuf_mutex */
/*------------------------------------- Insert buffer tree */ /*------------------------------------- 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_MUTEX 351
#define SYNC_IBUF_BITMAP 350 #define SYNC_IBUF_BITMAP 350
/*------------------------------------- MySQL query cache mutex */ /*------------------------------------- MySQL query cache mutex */
......
...@@ -1173,6 +1173,7 @@ sync_thread_add_level( ...@@ -1173,6 +1173,7 @@ sync_thread_add_level(
case SYNC_DICT_HEADER: case SYNC_DICT_HEADER:
case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_RWLOCK:
case SYNC_TRX_I_S_LAST_READ: case SYNC_TRX_I_S_LAST_READ:
case SYNC_IBUF_MUTEX:
if (!sync_thread_levels_g(array, level, TRUE)) { if (!sync_thread_levels_g(array, level, TRUE)) {
fprintf(stderr, fprintf(stderr,
"InnoDB: sync_thread_levels_g(array, %lu)" "InnoDB: sync_thread_levels_g(array, %lu)"
...@@ -1236,22 +1237,28 @@ sync_thread_add_level( ...@@ -1236,22 +1237,28 @@ sync_thread_add_level(
|| sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE));
break; break;
case SYNC_TREE_NODE_NEW: case SYNC_TREE_NODE_NEW:
ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE));
|| sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
break; break;
case SYNC_INDEX_TREE: case SYNC_INDEX_TREE:
if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE));
&& sync_thread_levels_contain(array, SYNC_FSP)) { break;
ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, case SYNC_IBUF_TREE_NODE:
TRUE)); 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 { } else {
ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, ut_a(sync_thread_levels_g(
TRUE)); array, SYNC_IBUF_TREE_NODE - 1, TRUE));
} }
break; break;
case SYNC_IBUF_MUTEX:
ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE));
break;
case SYNC_IBUF_PESS_INSERT_MUTEX: case SYNC_IBUF_PESS_INSERT_MUTEX:
ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE));
ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment