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(
ut_ad(zip_size == fil_space_get_zip_size(space));
ut_ad(ut_is_2pow(zip_size));
#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
buf_pool->stat.n_page_gets++;
fold = buf_page_address_fold(space, offset);
......
......@@ -656,22 +656,49 @@ ibuf_parse_bitmap_init(
return(ptr);
}
#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.
@return value of bits */
UNIV_INLINE
ulint
ibuf_bitmap_page_get_bits(
/*======================*/
ibuf_bitmap_page_get_bits_low(
/*==========================*/
const page_t* page, /*!< in: bitmap page */
ulint page_no,/*!< in: page whose bits to get */
ulint zip_size,/*!< in: compressed page size in bytes;
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, ... */
mtr_t* mtr __attribute__((unused)))
/*!< in: mtr containing an
x-latch to the bitmap page */
{
ulint byte_offset;
ulint bit_offset;
......@@ -683,7 +710,7 @@ ibuf_bitmap_page_get_bits(
# error "IBUF_BITS_PER_PAGE % 2 != 0"
#endif
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) {
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.
@return TRUE if level 2 or level 3 page */
UNIV_INTERN
ibool
ibuf_page(
/*======*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint page_no,/*!< in: page number */
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. */
ibuf_page_low(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint page_no,/*!< in: page number */
#ifdef UNIV_DEBUG
ibool x_latch,/*!< in: FALSE if relaxed check
(avoid latching the bitmap page) */
#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;
mtr_t local_mtr;
page_t* bitmap_page;
ut_ad(!recv_no_ibuf_operations);
ut_ad(x_latch || mtr == NULL);
if (ibuf_fixed_addr_page(space, zip_size, page_no)) {
......@@ -1135,12 +1170,55 @@ ibuf_page(
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) {
mtr = &local_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,
IBUF_BITMAP_IBUF, mtr);
......
......@@ -244,15 +244,44 @@ Must not be called when recv_no_ibuf_operations==TRUE.
@return TRUE if level 2 or level 3 page */
UNIV_INTERN
ibool
ibuf_page(
/*======*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint page_no,/*!< in: page number */
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. */
ibuf_page_low(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint page_no,/*!< in: page number */
#ifdef UNIV_DEBUG
ibool x_latch,/*!< in: FALSE if relaxed check
(avoid latching the bitmap page) */
#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
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