Commit 9bfb5ece authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#58212 Possible deadlock in change buffer in debug builds

ibuf_page(): Renamed to ibuf_page_low(). Add the parameters file, line
so that the latch diagnostics will be more meaningful.
In debug builds, add the parameter ibool x_latch. When x_latch=FALSE,
do not x-latch the page, but only buffer-fix it for reading the bit.
In UNIV_SYNC_DEBUG, display a message if an insert buffer bitmap page
was already latched. (The message should be displayed in those cases
where the code would have previously failed.)

ibuf_page(): A wrapper macro for ibuf_page_low(). Pass x_latch=TRUE.

ibuf_bitmap_page_get_bits(): Renamed to ibuf_bitmap_page_get_bits_low().
In UNIV_DEBUG, add the parameter latch_mode.
Remove the parameter mtr unless UNIV_DEBUG is defined.

ibuf_bitmap_page_get_bits(): A wrapper macro for
ibuf_bitmap_page_get_bits_low(). Pass latch_type=MTR_MEMO_PAGE_X_FIX.

buf_page_get_gen(): Use ibuf_page_low(x_latch=FALSE) in the debug assertion.
This avoids the possible deadlock.
parent d6bac7db
...@@ -2745,7 +2745,8 @@ buf_page_get_gen( ...@@ -2745,7 +2745,8 @@ buf_page_get_gen(
ut_ad(zip_size == fil_space_get_zip_size(space)); ut_ad(zip_size == fil_space_get_zip_size(space));
ut_ad(ut_is_2pow(zip_size)); ut_ad(ut_is_2pow(zip_size));
#ifndef UNIV_LOG_DEBUG #ifndef UNIV_LOG_DEBUG
ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL)); ut_ad(!ibuf_inside() || ibuf_page_low(space, zip_size, offset,
FALSE, file, line, NULL));
#endif #endif
buf_pool->stat.n_page_gets++; buf_pool->stat.n_page_gets++;
fold = buf_page_address_fold(space, offset); fold = buf_page_address_fold(space, offset);
......
...@@ -656,22 +656,49 @@ ibuf_parse_bitmap_init( ...@@ -656,22 +656,49 @@ ibuf_parse_bitmap_init(
return(ptr); return(ptr);
} }
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
# ifdef UNIV_DEBUG
/** Gets the desired bits for a given page from a bitmap page.
@param page in: bitmap page
@param offset in: page whose bits to get
@param zs in: compressed page size in bytes; 0 for uncompressed pages
@param bit in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ...
@param mtr in: mini-transaction holding an x-latch on the bitmap page
@return value of bits */
# define ibuf_bitmap_page_get_bits(page, offset, zs, bit, mtr) \
ibuf_bitmap_page_get_bits_low(page, offset, zs, \
MTR_MEMO_PAGE_X_FIX, mtr, bit)
# else /* UNIV_DEBUG */
/** Gets the desired bits for a given page from a bitmap page.
@param page in: bitmap page
@param offset in: page whose bits to get
@param zs in: compressed page size in bytes; 0 for uncompressed pages
@param bit in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ...
@param mtr in: mini-transaction holding an x-latch on the bitmap page
@return value of bits */
# define ibuf_bitmap_page_get_bits(page, offset, zs, bit, mtr) \
ibuf_bitmap_page_get_bits_low(page, offset, zs, bit)
# endif /* UNIV_DEBUG */
/********************************************************************//** /********************************************************************//**
Gets the desired bits for a given page from a bitmap page. Gets the desired bits for a given page from a bitmap page.
@return value of bits */ @return value of bits */
UNIV_INLINE UNIV_INLINE
ulint ulint
ibuf_bitmap_page_get_bits( ibuf_bitmap_page_get_bits_low(
/*======================*/ /*==========================*/
const page_t* page, /*!< in: bitmap page */ const page_t* page, /*!< in: bitmap page */
ulint page_no,/*!< in: page whose bits to get */ ulint page_no,/*!< in: page whose bits to get */
ulint zip_size,/*!< in: compressed page size in bytes; ulint zip_size,/*!< in: compressed page size in bytes;
0 for uncompressed pages */ 0 for uncompressed pages */
ulint bit, /*!< in: IBUF_BITMAP_FREE, #ifdef UNIV_DEBUG
ulint latch_type,
/*!< in: MTR_MEMO_PAGE_X_FIX,
MTR_MEMO_BUF_FIX, ... */
mtr_t* mtr, /*!< in: mini-transaction holding latch_type
on the bitmap page */
#endif /* UNIV_DEBUG */
ulint bit) /*!< in: IBUF_BITMAP_FREE,
IBUF_BITMAP_BUFFERED, ... */ IBUF_BITMAP_BUFFERED, ... */
mtr_t* mtr __attribute__((unused)))
/*!< in: mtr containing an
x-latch to the bitmap page */
{ {
ulint byte_offset; ulint byte_offset;
ulint bit_offset; ulint bit_offset;
...@@ -683,7 +710,7 @@ ibuf_bitmap_page_get_bits( ...@@ -683,7 +710,7 @@ ibuf_bitmap_page_get_bits(
# error "IBUF_BITS_PER_PAGE % 2 != 0" # error "IBUF_BITS_PER_PAGE % 2 != 0"
#endif #endif
ut_ad(ut_is_2pow(zip_size)); ut_ad(ut_is_2pow(zip_size));
ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains_page(mtr, page, latch_type));
if (!zip_size) { if (!zip_size) {
bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
...@@ -1109,21 +1136,29 @@ Must not be called when recv_no_ibuf_operations==TRUE. ...@@ -1109,21 +1136,29 @@ Must not be called when recv_no_ibuf_operations==TRUE.
@return TRUE if level 2 or level 3 page */ @return TRUE if level 2 or level 3 page */
UNIV_INTERN UNIV_INTERN
ibool ibool
ibuf_page( ibuf_page_low(
/*======*/ /*==========*/
ulint space, /*!< in: space id */ ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint page_no,/*!< in: page number */ ulint page_no,/*!< in: page number */
mtr_t* mtr) /*!< in: mtr which will contain an x-latch to the #ifdef UNIV_DEBUG
bitmap page if the page is not one of the fixed ibool x_latch,/*!< in: FALSE if relaxed check
address ibuf pages, or NULL, in which case a new (avoid latching the bitmap page) */
transaction is created. */ #endif /* UNIV_DEBUG */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mtr which will contain an
x-latch to the bitmap page if the page
is not one of the fixed address ibuf
pages, or NULL, in which case a new
transaction is created. */
{ {
ibool ret; ibool ret;
mtr_t local_mtr; mtr_t local_mtr;
page_t* bitmap_page; page_t* bitmap_page;
ut_ad(!recv_no_ibuf_operations); ut_ad(!recv_no_ibuf_operations);
ut_ad(x_latch || mtr == NULL);
if (ibuf_fixed_addr_page(space, zip_size, page_no)) { if (ibuf_fixed_addr_page(space, zip_size, page_no)) {
...@@ -1135,12 +1170,55 @@ ibuf_page( ...@@ -1135,12 +1170,55 @@ ibuf_page(
ut_ad(fil_space_get_type(IBUF_SPACE_ID) == FIL_TABLESPACE); ut_ad(fil_space_get_type(IBUF_SPACE_ID) == FIL_TABLESPACE);
#ifdef UNIV_DEBUG
if (!x_latch) {
mtr_start(&local_mtr);
/* Get the bitmap page without a page latch, so that
we will not be violating the latching order when
another bitmap page has already been latched by this
thread. The page will be buffer-fixed, and thus it
cannot be removed or relocated while we are looking at
it. The contents of the page could change, but the
IBUF_BITMAP_IBUF bit that we are interested in should
not be modified by any other thread. Nobody should be
calling ibuf_add_free_page() or ibuf_remove_free_page()
while the page is linked to the insert buffer b-tree. */
bitmap_page = buf_block_get_frame(
buf_page_get_gen(
space, zip_size,
ibuf_bitmap_page_no_calc(zip_size, page_no),
RW_NO_LATCH, NULL, BUF_GET_NO_LATCH,
file, line, &local_mtr));
# ifdef UNIV_SYNC_DEBUG
/* This is for tracking Bug #58212. This check and message can
be removed once it has been established that our assumptions
about this condition are correct. The bug was only a one-time
occurrence, unable to repeat since then. */
void* latch = sync_thread_levels_contains(SYNC_IBUF_BITMAP);
if (latch) {
fprintf(stderr, "Bug#58212 UNIV_SYNC_DEBUG"
" levels %p (%u,%u)\n",
latch, (unsigned) space, (unsigned) page_no);
}
# endif /* UNIV_SYNC_DEBUG */
ret = ibuf_bitmap_page_get_bits_low(
bitmap_page, page_no, zip_size,
MTR_MEMO_BUF_FIX, &local_mtr, IBUF_BITMAP_IBUF);
mtr_commit(&local_mtr);
return(ret);
}
#endif /* UNIV_DEBUG */
if (mtr == NULL) { if (mtr == NULL) {
mtr = &local_mtr; mtr = &local_mtr;
mtr_start(mtr); mtr_start(mtr);
} }
bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr); bitmap_page = ibuf_bitmap_get_map_page_func(space, page_no, zip_size,
file, line, mtr);
ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size, ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
IBUF_BITMAP_IBUF, mtr); IBUF_BITMAP_IBUF, mtr);
......
...@@ -244,15 +244,44 @@ Must not be called when recv_no_ibuf_operations==TRUE. ...@@ -244,15 +244,44 @@ Must not be called when recv_no_ibuf_operations==TRUE.
@return TRUE if level 2 or level 3 page */ @return TRUE if level 2 or level 3 page */
UNIV_INTERN UNIV_INTERN
ibool ibool
ibuf_page( ibuf_page_low(
/*======*/ /*==========*/
ulint space, /*!< in: space id */ ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint page_no,/*!< in: page number */ ulint page_no,/*!< in: page number */
mtr_t* mtr); /*!< in: mtr which will contain an x-latch to the #ifdef UNIV_DEBUG
bitmap page if the page is not one of the fixed ibool x_latch,/*!< in: FALSE if relaxed check
address ibuf pages, or NULL, in which case a new (avoid latching the bitmap page) */
transaction is created. */ #endif /* UNIV_DEBUG */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mtr which will contain an
x-latch to the bitmap page if the page
is not one of the fixed address ibuf
pages, or NULL, in which case a new
transaction is created. */
__attribute__((warn_unused_result));
#ifdef UNIV_DEBUG
/** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of
pages. Must not be called when recv_no_ibuf_operations==TRUE.
@param space tablespace identifier
@param zip_size compressed page size in bytes, or 0
@param page_no page number
@param mtr mini-transaction or NULL
@return TRUE if level 2 or level 3 page */
# define ibuf_page(space, zip_size, page_no, mtr) \
ibuf_page_low(space, zip_size, page_no, TRUE, __FILE__, __LINE__, mtr)
#else /* UVIV_DEBUG */
/** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of
pages. Must not be called when recv_no_ibuf_operations==TRUE.
@param space tablespace identifier
@param zip_size compressed page size in bytes, or 0
@param page_no page number
@param mtr mini-transaction or NULL
@return TRUE if level 2 or level 3 page */
# define ibuf_page(space, zip_size, page_no, mtr) \
ibuf_page_low(space, zip_size, page_no, __FILE__, __LINE__, mtr)
#endif /* UVIV_DEBUG */
/***********************************************************************//** /***********************************************************************//**
Frees excess pages from the ibuf free list. This function is called when an OS Frees excess pages from the ibuf free list. This function is called when an OS
thread calls fsp services to allocate a new file segment, or a new page to a thread calls fsp services to allocate a new file segment, or a new page to a
......
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