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

MDEV-25491: Race condition between DROP TABLE and purge of SYS_INDEXES record

btr_free_if_exists(): Always use the BUF_GET_POSSIBLY_FREED mode
when accessing pages, because due to MDEV-24589 the function
fil_space_t::set_stopping(true) can be called at any time during
the execution of this function.

mtr_t::m_freeing_tree: New data member for debugging purposes.

buf_page_get_low(): Assert that the BUF_GET mode is not being used
anywhere during the execution of btr_free_if_exists().

In all code related to freeing or allocating pages, we will add some
robustness, by making more use of BUF_GET_POSSIBLY_FREED and by
reporting an error instead of crashing in some cases of corruption.
parent a81aec15
...@@ -939,9 +939,11 @@ static void btr_free_root(buf_block_t *block, mtr_t *mtr) ...@@ -939,9 +939,11 @@ static void btr_free_root(buf_block_t *block, mtr_t *mtr)
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
/* Free the entire segment in small steps. */ /* Free the entire segment in small steps. */
ut_d(mtr->freeing_tree());
while (!fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_TOP + block->frame, mtr)); while (!fseg_free_step(PAGE_HEADER + PAGE_BTR_SEG_TOP + block->frame, mtr));
} }
MY_ATTRIBUTE((warn_unused_result))
/** Prepare to free a B-tree. /** Prepare to free a B-tree.
@param[in] page_id page id @param[in] page_id page id
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
...@@ -949,33 +951,29 @@ static void btr_free_root(buf_block_t *block, mtr_t *mtr) ...@@ -949,33 +951,29 @@ static void btr_free_root(buf_block_t *block, mtr_t *mtr)
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return root block, to invoke btr_free_but_not_root() and btr_free_root() @return root block, to invoke btr_free_but_not_root() and btr_free_root()
@retval NULL if the page is no longer a matching B-tree page */ @retval NULL if the page is no longer a matching B-tree page */
static MY_ATTRIBUTE((warn_unused_result)) static
buf_block_t* buf_block_t *btr_free_root_check(const page_id_t page_id, ulint zip_size,
btr_free_root_check( index_id_t index_id, mtr_t *mtr)
const page_id_t page_id,
ulint zip_size,
index_id_t index_id,
mtr_t* mtr)
{ {
ut_ad(page_id.space() != SRV_TMP_SPACE_ID); ut_ad(page_id.space() != SRV_TMP_SPACE_ID);
ut_ad(index_id != BTR_FREED_INDEX_ID); ut_ad(index_id != BTR_FREED_INDEX_ID);
buf_block_t* block = buf_page_get( buf_block_t *block= buf_page_get_gen(page_id, zip_size, RW_X_LATCH,
page_id, zip_size, RW_X_LATCH, mtr); nullptr, BUF_GET_POSSIBLY_FREED, mtr);
if (block) { if (!block);
if (fil_page_index_page_check(block->frame) else if (block->page.status == buf_page_t::FREED)
&& index_id == btr_page_get_index_id(block->frame)) { block= nullptr;
/* This should be a root page. else if (fil_page_index_page_check(block->frame) &&
It should not be possible to reassign the same index_id == btr_page_get_index_id(block->frame))
index_id for some other index in the tablespace. */ /* This should be a root page. It should not be possible to
ut_ad(!page_has_siblings(block->frame)); reassign the same index_id for some other index in the
} else { tablespace. */
block = NULL; ut_ad(!page_has_siblings(block->frame));
} else
} block= nullptr;
return(block); return block;
} }
/** Initialize the root page of the b-tree /** Initialize the root page of the b-tree
...@@ -1131,6 +1129,7 @@ btr_free_but_not_root( ...@@ -1131,6 +1129,7 @@ btr_free_but_not_root(
ut_ad(!page_has_siblings(block->frame)); ut_ad(!page_has_siblings(block->frame));
leaf_loop: leaf_loop:
mtr_start(&mtr); mtr_start(&mtr);
ut_d(mtr.freeing_tree());
mtr_set_log_mode(&mtr, log_mode); mtr_set_log_mode(&mtr, log_mode);
mtr.set_named_space_id(block->page.id().space()); mtr.set_named_space_id(block->page.id().space());
...@@ -1230,23 +1229,20 @@ void dict_index_t::clear(que_thr_t *thr) ...@@ -1230,23 +1229,20 @@ void dict_index_t::clear(que_thr_t *thr)
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
@param[in] index_id PAGE_INDEX_ID contents @param[in] index_id PAGE_INDEX_ID contents
@param[in,out] mtr mini-transaction */ @param[in,out] mtr mini-transaction */
void void btr_free_if_exists(const page_id_t page_id, ulint zip_size,
btr_free_if_exists( index_id_t index_id, mtr_t *mtr)
const page_id_t page_id,
ulint zip_size,
index_id_t index_id,
mtr_t* mtr)
{ {
buf_block_t* root = btr_free_root_check( if (fil_space_t *space= fil_space_t::get(page_id.space()))
page_id, zip_size, index_id, mtr); {
if (buf_block_t *root= btr_free_root_check(page_id, zip_size, index_id,
if (root == NULL) { mtr))
return; {
} btr_free_but_not_root(root, mtr->get_log_mode());
mtr->set_named_space(space);
btr_free_but_not_root(root, mtr->get_log_mode()); btr_free_root(root, mtr);
mtr->set_named_space_id(page_id.space()); }
btr_free_root(root, mtr); space->release();
}
} }
/** Free an index tree in a temporary tablespace. /** Free an index tree in a temporary tablespace.
......
...@@ -2585,6 +2585,7 @@ buf_page_get_low( ...@@ -2585,6 +2585,7 @@ buf_page_get_low(
/* fall through */ /* fall through */
case BUF_GET: case BUF_GET:
case BUF_GET_IF_IN_POOL_OR_WATCH: case BUF_GET_IF_IN_POOL_OR_WATCH:
ut_ad(!mtr->is_freeing_tree());
fil_space_t* s = fil_space_get(page_id.space()); fil_space_t* s = fil_space_get(page_id.space());
ut_ad(s); ut_ad(s);
ut_ad(s->zip_size() == zip_size); ut_ad(s->zip_size() == zip_size);
......
...@@ -125,13 +125,16 @@ fseg_alloc_free_page_low( ...@@ -125,13 +125,16 @@ fseg_alloc_free_page_low(
@param[in] space tablespace @param[in] space tablespace
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return pointer to the space header, page x-locked */ @return pointer to the space header, page x-locked */
inline buf_block_t *fsp_get_header(const fil_space_t *space, mtr_t *mtr) static buf_block_t *fsp_get_header(const fil_space_t *space, mtr_t *mtr)
{ {
buf_block_t *block= buf_page_get(page_id_t(space->id, 0), space->zip_size(), buf_block_t *block= buf_page_get_gen(page_id_t(space->id, 0),
RW_SX_LATCH, mtr); space->zip_size(), RW_SX_LATCH,
ut_ad(space->id == mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + nullptr, BUF_GET_POSSIBLY_FREED, mtr);
block->frame)); if (!block || block->page.status == buf_page_t::FREED)
return block; return nullptr;
ut_ad(space->id == mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_ID +
block->frame));
return block;
} }
/** Set the XDES_FREE_BIT of a page. /** Set the XDES_FREE_BIT of a page.
...@@ -302,8 +305,8 @@ fseg_mark_page_used(fseg_inode_t *seg_inode, buf_block_t *iblock, ...@@ -302,8 +305,8 @@ fseg_mark_page_used(fseg_inode_t *seg_inode, buf_block_t *iblock,
@param[in,out] sp_header tablespace header page, x-latched @param[in,out] sp_header tablespace header page, x-latched
@param[in] space tablespace @param[in] space tablespace
@param[in] offset page offset @param[in] offset page offset
@param[out] desc_block descriptor block
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@param[out] desc_block descriptor block
@param[in] init_space whether the tablespace is being initialized @param[in] init_space whether the tablespace is being initialized
@return pointer to the extent descriptor, NULL if the page does not @return pointer to the extent descriptor, NULL if the page does not
exist in the space or if the offset exceeds free limit */ exist in the space or if the offset exceeds free limit */
...@@ -313,8 +316,8 @@ xdes_get_descriptor_with_space_hdr( ...@@ -313,8 +316,8 @@ xdes_get_descriptor_with_space_hdr(
buf_block_t* header, buf_block_t* header,
const fil_space_t* space, const fil_space_t* space,
page_no_t offset, page_no_t offset,
buf_block_t** desc_block,
mtr_t* mtr, mtr_t* mtr,
buf_block_t** desc_block = nullptr,
bool init_space = false) bool init_space = false)
{ {
ut_ad(space->is_owner()); ut_ad(space->is_owner());
...@@ -368,15 +371,18 @@ defined, as they are uninitialized above the free limit. ...@@ -368,15 +371,18 @@ defined, as they are uninitialized above the free limit.
@param[in] space tablespace @param[in] space tablespace
@param[in] offset page offset; if equal to the free limit, we @param[in] offset page offset; if equal to the free limit, we
try to add new extents to the space free list try to add new extents to the space free list
@param[out] xdes extent descriptor page
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@param[out] xdes extent descriptor page
@return the extent descriptor */ @return the extent descriptor */
static xdes_t* xdes_get_descriptor(const fil_space_t *space, page_no_t offset, static xdes_t *xdes_get_descriptor(const fil_space_t *space, page_no_t offset,
buf_block_t **xdes, mtr_t *mtr) mtr_t *mtr, buf_block_t **xdes= nullptr)
{ {
buf_block_t *block= buf_page_get(page_id_t(space->id, 0), space->zip_size(), buf_block_t *block= buf_page_get_gen(page_id_t(space->id, 0),
RW_SX_LATCH, mtr); space->zip_size(), RW_SX_LATCH,
return xdes_get_descriptor_with_space_hdr(block, space, offset, xdes, mtr); nullptr, BUF_GET_POSSIBLY_FREED, mtr);
if (!block || block->page.status == buf_page_t::FREED)
return nullptr;
return xdes_get_descriptor_with_space_hdr(block, space, offset, mtr, xdes);
} }
/** Get the extent descriptor of a page. /** Get the extent descriptor of a page.
...@@ -429,27 +435,23 @@ xdes_get_descriptor_const( ...@@ -429,27 +435,23 @@ xdes_get_descriptor_const(
return(NULL); return(NULL);
} }
MY_ATTRIBUTE((nonnull(3), warn_unused_result))
/** Get a pointer to the extent descriptor. The page where the /** Get a pointer to the extent descriptor. The page where the
extent descriptor resides is x-locked. extent descriptor resides is x-locked.
@param[in] space tablespace @param space tablespace
@param[in] lst_node file address of the list node @param lst_node file address of the list node contained in the descriptor
contained in the descriptor @param mode BUF_GET or BUF_GET_POSSIBLY_FREED
@param[out] block extent descriptor block @param mtr mini-transaction
@param[in,out] mtr mini-transaction @param block extent descriptor block
@return pointer to the extent descriptor */ @return pointer to the extent descriptor */
MY_ATTRIBUTE((nonnull, warn_unused_result)) static inline
UNIV_INLINE xdes_t *xdes_lst_get_descriptor(const fil_space_t &space, fil_addr_t lst_node,
xdes_t* mtr_t *mtr, buf_block_t **block= nullptr)
xdes_lst_get_descriptor(
const fil_space_t* space,
fil_addr_t lst_node,
buf_block_t** block,
mtr_t* mtr)
{ {
ut_ad(mtr->memo_contains(*space)); ut_ad(mtr->memo_contains(space));
return fut_get_ptr(space->id, space->zip_size(), auto b= fut_get_ptr(space.id, space.zip_size(), lst_node, RW_SX_LATCH,
lst_node, RW_SX_LATCH, mtr, block) mtr, block);
- XDES_FLST_NODE; return b ? b - XDES_FLST_NODE : nullptr;
} }
/********************************************************************//** /********************************************************************//**
...@@ -904,7 +906,12 @@ fsp_fill_free_list( ...@@ -904,7 +906,12 @@ fsp_fill_free_list(
buf_block_t* xdes = nullptr; buf_block_t* xdes = nullptr;
xdes_t* descr = xdes_get_descriptor_with_space_hdr( xdes_t* descr = xdes_get_descriptor_with_space_hdr(
header, space, i, &xdes, mtr, init_space); header, space, i, mtr, &xdes, init_space);
if (!descr) {
ut_ad("corruption" == 0);
return;
}
if (xdes != header && !space->full_crc32()) { if (xdes != header && !space->full_crc32()) {
fil_block_check_type(*xdes, FIL_PAGE_TYPE_XDES, mtr); fil_block_check_type(*xdes, FIL_PAGE_TYPE_XDES, mtr);
} }
...@@ -957,18 +964,26 @@ fsp_alloc_free_extent( ...@@ -957,18 +964,26 @@ fsp_alloc_free_extent(
{ {
fil_addr_t first; fil_addr_t first;
xdes_t* descr; xdes_t* descr;
buf_block_t* desc_block = NULL; buf_block_t* desc_block;
buf_block_t* header = fsp_get_header(space, mtr); buf_block_t* header = fsp_get_header(space, mtr);
if (!header) {
ut_ad("corruption" == 0);
return nullptr;
}
descr = xdes_get_descriptor_with_space_hdr( descr = xdes_get_descriptor_with_space_hdr(
header, space, hint, &desc_block, mtr); header, space, hint, mtr, &desc_block);
if (!descr) {
ut_ad("corruption" == 0);
return nullptr;
}
if (desc_block != header && !space->full_crc32()) { if (desc_block != header && !space->full_crc32()) {
fil_block_check_type(*desc_block, FIL_PAGE_TYPE_XDES, mtr); fil_block_check_type(*desc_block, FIL_PAGE_TYPE_XDES, mtr);
} }
if (descr && (xdes_get_state(descr) == XDES_FREE)) { if (xdes_get_state(descr) == XDES_FREE) {
/* Ok, we can take this extent */ /* Ok, we can take this extent */
} else { } else {
/* Take the first extent in the free list */ /* Take the first extent in the free list */
...@@ -985,8 +1000,12 @@ fsp_alloc_free_extent( ...@@ -985,8 +1000,12 @@ fsp_alloc_free_extent(
} }
} }
descr = xdes_lst_get_descriptor(space, first, &desc_block, descr = xdes_lst_get_descriptor(*space, first, mtr,
mtr); &desc_block);
if (!descr) {
ut_ad("corruption" == 0);
return nullptr;
}
} }
flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE, desc_block, flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE, desc_block,
...@@ -1073,11 +1092,16 @@ fsp_alloc_free_page( ...@@ -1073,11 +1092,16 @@ fsp_alloc_free_page(
ut_d(space->modify_check(*mtr)); ut_d(space->modify_check(*mtr));
buf_block_t* block = fsp_get_header(space, mtr); buf_block_t* block = fsp_get_header(space, mtr);
if (!block) {
return nullptr;
}
buf_block_t *xdes; buf_block_t *xdes;
/* Get the hinted descriptor */ /* Get the hinted descriptor */
descr = xdes_get_descriptor_with_space_hdr(block, space, hint, &xdes, descr = xdes_get_descriptor_with_space_hdr(block, space, hint, mtr,
mtr); &xdes);
if (descr && (xdes_get_state(descr) == XDES_FREE_FRAG)) { if (descr && (xdes_get_state(descr) == XDES_FREE_FRAG)) {
/* Ok, we can take this extent */ /* Ok, we can take this extent */
...@@ -1096,10 +1120,9 @@ fsp_alloc_free_page( ...@@ -1096,10 +1120,9 @@ fsp_alloc_free_page(
descr = fsp_alloc_free_extent(space, hint, &xdes, mtr); descr = fsp_alloc_free_extent(space, hint, &xdes, mtr);
if (descr == NULL) { if (!descr) {
/* No free space left */ /* No free space left */
return nullptr;
return(NULL);
} }
xdes_set_state(*xdes, descr, XDES_FREE_FRAG, mtr); xdes_set_state(*xdes, descr, XDES_FREE_FRAG, mtr);
...@@ -1108,8 +1131,12 @@ fsp_alloc_free_page( ...@@ -1108,8 +1131,12 @@ fsp_alloc_free_page(
descr - xdes->frame descr - xdes->frame
+ XDES_FLST_NODE), mtr); + XDES_FLST_NODE), mtr);
} else { } else {
descr = xdes_lst_get_descriptor(space, first, &xdes, descr = xdes_lst_get_descriptor(*space, first, mtr,
mtr); &xdes);
if (!descr) {
ut_ad("corruption" == 0);
return nullptr;
}
} }
/* Reset the hint */ /* Reset the hint */
...@@ -1121,11 +1148,11 @@ fsp_alloc_free_page( ...@@ -1121,11 +1148,11 @@ fsp_alloc_free_page(
uint32_t free = xdes_find_free(descr, hint % FSP_EXTENT_SIZE); uint32_t free = xdes_find_free(descr, hint % FSP_EXTENT_SIZE);
if (free == FIL_NULL) { if (free == FIL_NULL) {
ib::error() << "Allocation metadata for file '"
ut_print_buf(stderr, ((byte*) descr) - 500, 1000); << space->chain.start->name
putc('\n', stderr); << "' is corrupted";
ut_ad("corruption" == 0);
ut_error; return nullptr;
} }
uint32_t page_no = xdes_get_offset(descr) + free; uint32_t page_no = xdes_get_offset(descr) + free;
...@@ -1178,10 +1205,18 @@ static void fsp_free_page(fil_space_t* space, page_no_t offset, mtr_t* mtr) ...@@ -1178,10 +1205,18 @@ static void fsp_free_page(fil_space_t* space, page_no_t offset, mtr_t* mtr)
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */ /* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
buf_block_t* header = fsp_get_header(space, mtr); buf_block_t* header = fsp_get_header(space, mtr);
buf_block_t* xdes= 0; if (!header) {
ut_ad(space->is_stopping());
return;
}
buf_block_t* xdes;
descr = xdes_get_descriptor_with_space_hdr(header, space, offset, descr = xdes_get_descriptor_with_space_hdr(header, space, offset, mtr,
&xdes, mtr); &xdes);
if (!descr) {
ut_ad(space->is_stopping());
return;
}
state = xdes_get_state(descr); state = xdes_get_state(descr);
...@@ -1263,10 +1298,17 @@ static void fsp_free_extent(fil_space_t* space, page_no_t offset, mtr_t* mtr) ...@@ -1263,10 +1298,17 @@ static void fsp_free_extent(fil_space_t* space, page_no_t offset, mtr_t* mtr)
ut_ad(space->is_owner()); ut_ad(space->is_owner());
buf_block_t *block= fsp_get_header(space, mtr); buf_block_t *block= fsp_get_header(space, mtr);
buf_block_t *xdes= 0; if (!block)
return;
buf_block_t *xdes;
xdes_t* descr= xdes_get_descriptor_with_space_hdr(block, space, offset, mtr,
&xdes);
if (!descr)
{
ut_ad(space->is_stopping());
return;
}
xdes_t* descr= xdes_get_descriptor_with_space_hdr(block, space, offset,
&xdes, mtr);
ut_a(xdes_get_state(descr) != XDES_FREE); ut_a(xdes_get_state(descr) != XDES_FREE);
xdes_init(*xdes, descr, mtr); xdes_init(*xdes, descr, mtr);
...@@ -1441,6 +1483,9 @@ static void fsp_free_seg_inode( ...@@ -1441,6 +1483,9 @@ static void fsp_free_seg_inode(
ut_d(space->modify_check(*mtr)); ut_d(space->modify_check(*mtr));
buf_block_t* header = fsp_get_header(space, mtr); buf_block_t* header = fsp_get_header(space, mtr);
if (!header) {
return;
}
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
...@@ -1489,11 +1534,11 @@ fseg_inode_try_get( ...@@ -1489,11 +1534,11 @@ fseg_inode_try_get(
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET); inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE)); ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
inode = fut_get_ptr(space, zip_size, inode_addr, RW_SX_LATCH, mtr, inode = fut_get_ptr(space, zip_size, inode_addr, RW_SX_LATCH,
block); mtr, block);
if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
if (UNIV_UNLIKELY(!inode)) {
} else if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
inode = NULL; inode = NULL;
} else { } else {
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
...@@ -1519,10 +1564,9 @@ fseg_inode_get( ...@@ -1519,10 +1564,9 @@ fseg_inode_get(
mtr_t* mtr, mtr_t* mtr,
buf_block_t** block = NULL) buf_block_t** block = NULL)
{ {
fseg_inode_t* inode fseg_inode_t *inode= fseg_inode_try_get(header, space, zip_size, mtr, block);
= fseg_inode_try_get(header, space, zip_size, mtr, block); ut_a(inode);
ut_a(inode); return inode;
return(inode);
} }
/** Get the page number from the nth fragment page slot. /** Get the page number from the nth fragment page slot.
...@@ -1669,6 +1713,11 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, ...@@ -1669,6 +1713,11 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr,
} }
buf_block_t* header = fsp_get_header(space, mtr); buf_block_t* header = fsp_get_header(space, mtr);
if (!header) {
ut_ad("corruption" == 0);
goto funct_exit;
}
buf_block_t* iblock; buf_block_t* iblock;
inode = fsp_alloc_seg_inode(space, header, &iblock, mtr); inode = fsp_alloc_seg_inode(space, header, &iblock, mtr);
...@@ -1823,7 +1872,7 @@ fseg_fill_free_list( ...@@ -1823,7 +1872,7 @@ fseg_fill_free_list(
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) { for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
buf_block_t* xdes; buf_block_t* xdes;
descr = xdes_get_descriptor(space, hint, &xdes, mtr); descr = xdes_get_descriptor(space, hint, mtr, &xdes);
if (!descr || (XDES_FREE != xdes_get_state(descr))) { if (!descr || (XDES_FREE != xdes_get_state(descr))) {
/* We cannot allocate the desired extent: stop */ /* We cannot allocate the desired extent: stop */
...@@ -1880,7 +1929,14 @@ fseg_alloc_free_extent( ...@@ -1880,7 +1929,14 @@ fseg_alloc_free_extent(
first = flst_get_first(inode + FSEG_FREE); first = flst_get_first(inode + FSEG_FREE);
descr = xdes_lst_get_descriptor(space, first, xdes, mtr); descr = xdes_lst_get_descriptor(*space, first, mtr, xdes);
if (UNIV_UNLIKELY(!descr)) {
ib::error() << "Allocation metadata for file '"
<< space->chain.start->name
<< "' is corrupted";
ut_ad("corruption" == 0);
return nullptr;
}
} else { } else {
/* Segment free list was empty, allocate from space */ /* Segment free list was empty, allocate from space */
descr = fsp_alloc_free_extent(space, 0, xdes, mtr); descr = fsp_alloc_free_extent(space, 0, xdes, mtr);
...@@ -1963,15 +2019,22 @@ fseg_alloc_free_page_low( ...@@ -1963,15 +2019,22 @@ fseg_alloc_free_page_low(
reserved = fseg_n_reserved_pages_low(seg_inode, &used); reserved = fseg_n_reserved_pages_low(seg_inode, &used);
buf_block_t* header = fsp_get_header(space, mtr); buf_block_t* header = fsp_get_header(space, mtr);
if (!header) {
ut_ad("corruption" == 0);
return nullptr;
}
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr,
&xdes, mtr); &xdes);
if (descr == NULL) { if (!descr) {
/* Hint outside space or too high above free limit: reset /* Hint outside space or too high above free limit: reset
hint */ hint */
/* The file space header page is always allocated. */ /* The file space header page is always allocated. */
hint = 0; hint = 0;
descr = xdes_get_descriptor(space, hint, &xdes, mtr); descr = xdes_get_descriptor(space, hint, mtr, &xdes);
if (!descr) {
return nullptr;
}
} }
/* In the big if-else below we look for ret_page and ret_descr */ /* In the big if-else below we look for ret_page and ret_descr */
...@@ -2066,7 +2129,15 @@ fseg_alloc_free_page_low( ...@@ -2066,7 +2129,15 @@ fseg_alloc_free_page_low(
return(NULL); return(NULL);
} }
ret_descr = xdes_lst_get_descriptor(space, first, &xdes, mtr); ret_descr = xdes_lst_get_descriptor(*space, first, mtr, &xdes);
if (!ret_descr) {
ib::error() << "Allocation metadata for file '"
<< space->chain.start->name
<< "' is corrupted";
ut_ad("corruption" == 0);
return nullptr;
}
ret_page = xdes_find_free(ret_descr); ret_page = xdes_find_free(ret_descr);
if (ret_page == FIL_NULL) { if (ret_page == FIL_NULL) {
ut_ad(!has_done_reservation); ut_ad(!has_done_reservation);
...@@ -2150,7 +2221,7 @@ fseg_alloc_free_page_low( ...@@ -2150,7 +2221,7 @@ fseg_alloc_free_page_low(
or FSEG_FREE), and the page is not yet marked as used. */ or FSEG_FREE), and the page is not yet marked as used. */
ut_d(buf_block_t* xxdes); ut_d(buf_block_t* xxdes);
ut_ad(xdes_get_descriptor(space, ret_page, &xxdes, mtr) ut_ad(xdes_get_descriptor(space, ret_page, mtr, &xxdes)
== ret_descr); == ret_descr);
ut_ad(xdes == xxdes); ut_ad(xdes == xxdes);
ut_ad(xdes_is_free(ret_descr, ret_page % FSP_EXTENT_SIZE)); ut_ad(xdes_is_free(ret_descr, ret_page % FSP_EXTENT_SIZE));
...@@ -2252,12 +2323,16 @@ fsp_reserve_free_pages( ...@@ -2252,12 +2323,16 @@ fsp_reserve_free_pages(
ut_a(!is_system_tablespace(space->id)); ut_a(!is_system_tablespace(space->id));
ut_a(size < FSP_EXTENT_SIZE); ut_a(size < FSP_EXTENT_SIZE);
buf_block_t* xdes; descr = xdes_get_descriptor_with_space_hdr(header, space, 0, mtr);
descr = xdes_get_descriptor_with_space_hdr(header, space, 0, &xdes, if (!descr) {
mtr); return false;
}
uint32_t n_used = xdes_get_n_used(descr); uint32_t n_used = xdes_get_n_used(descr);
ut_a(n_used <= size); if (n_used > size) {
ut_ad("corruption" == 0);
return false;
}
return(size >= n_used + n_pages return(size >= n_used + n_pages
|| fsp_try_extend_data_file_with_pages( || fsp_try_extend_data_file_with_pages(
...@@ -2323,6 +2398,9 @@ fsp_reserve_free_extents( ...@@ -2323,6 +2398,9 @@ fsp_reserve_free_extents(
const unsigned physical_size = space->physical_size(); const unsigned physical_size = space->physical_size();
buf_block_t* header = fsp_get_header(space, mtr); buf_block_t* header = fsp_get_header(space, mtr);
if (!header) {
ut_ad("corruption" == 0);
}
try_again: try_again:
uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE
+ header->frame); + header->frame);
...@@ -2446,16 +2524,16 @@ fseg_free_page_low( ...@@ -2446,16 +2524,16 @@ fseg_free_page_low(
const uint32_t extent_size = FSP_EXTENT_SIZE; const uint32_t extent_size = FSP_EXTENT_SIZE;
ut_ad(ut_is_2pow(extent_size)); ut_ad(ut_is_2pow(extent_size));
buf_block_t* xdes; buf_block_t* xdes;
xdes_t* descr = xdes_get_descriptor(space, offset, &xdes, mtr); xdes_t* descr = xdes_get_descriptor(space, offset, mtr, &xdes);
if (xdes_is_free(descr, offset & (extent_size - 1))) { if (!descr || xdes_is_free(descr, offset & (extent_size - 1))) {
ib::fatal() << "InnoDB is trying to free page " if (space->is_stopping()) {
<< page_id_t(space->id, offset) return;
<< " though it is already marked as free in the" }
" tablespace! The tablespace free space info is" ib::error() << "Page " << offset << " in file '"
" corrupt. You may need to dump your tables and" << space->chain.start->name
" recreate the whole database!" << "' is already marked as free";
<< FORCE_RECOVERY_MSG; return;
} }
if (xdes_get_state(descr) != XDES_FSEG) { if (xdes_get_state(descr) != XDES_FSEG) {
...@@ -2483,18 +2561,12 @@ fseg_free_page_low( ...@@ -2483,18 +2561,12 @@ fseg_free_page_low(
seg_id = mach_read_from_8(seg_inode + FSEG_ID); seg_id = mach_read_from_8(seg_inode + FSEG_ID);
if (UNIV_UNLIKELY(descr_id != seg_id)) { if (UNIV_UNLIKELY(descr_id != seg_id)) {
fputs("InnoDB: Dump of the tablespace extent descriptor: ", ib::error() << "InnoDB is trying to free page " << offset
stderr); << " in file '" << space->chain.start->name
ut_print_buf(stderr, descr, 40); << "' which does not belong to segment "
fputs("\nInnoDB: Dump of the segment inode: ", stderr); << descr_id
ut_print_buf(stderr, seg_inode, 40); << " but belongs to segment " << seg_id;
putc('\n', stderr); return;
ib::fatal() << "InnoDB is trying to free page "
<< page_id_t(space->id, offset)
<< ", which does not belong to segment " << descr_id
<< " but belongs to segment " << seg_id << "."
<< FORCE_RECOVERY_MSG;
} }
byte* p_not_full = seg_inode + FSEG_NOT_FULL_N_USED; byte* p_not_full = seg_inode + FSEG_NOT_FULL_N_USED;
...@@ -2538,36 +2610,29 @@ fseg_free_page_low( ...@@ -2538,36 +2610,29 @@ fseg_free_page_low(
@param[in] offset page number @param[in] offset page number
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@param[in] have_latch whether space->x_lock() was already called */ @param[in] have_latch whether space->x_lock() was already called */
void void fseg_free_page(fseg_header_t *seg_header, fil_space_t *space,
fseg_free_page( uint32_t offset, mtr_t *mtr, bool have_latch)
fseg_header_t* seg_header,
fil_space_t* space,
uint32_t offset,
mtr_t* mtr,
bool have_latch)
{ {
DBUG_ENTER("fseg_free_page"); DBUG_ENTER("fseg_free_page");
fseg_inode_t* seg_inode; buf_block_t *iblock;
buf_block_t* iblock; if (have_latch)
if (have_latch) { ut_ad(space->is_owner());
ut_ad(space->is_owner()); else
} else { mtr->x_lock_space(space);
mtr->x_lock_space(space);
} DBUG_PRINT("fseg_free_page",
("space_id: " ULINTPF ", page_no: %u", space->id, offset));
DBUG_LOG("fseg_free_page", "space_id: " << space->id
<< ", page_no: " << offset); if (fseg_inode_t *seg_inode= fseg_inode_try_get(seg_header,
space->id, space->zip_size(),
seg_inode = fseg_inode_get(seg_header, space->id, space->zip_size(), mtr, &iblock))
mtr, {
&iblock); if (!space->full_crc32())
if (!space->full_crc32()) { fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr);
fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr); fseg_free_page_low(seg_inode, iblock, space, offset, mtr);
} }
fseg_free_page_low(seg_inode, iblock, space, offset, mtr);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/** Determine whether a page is free. /** Determine whether a page is free.
...@@ -2619,11 +2684,13 @@ fseg_free_extent( ...@@ -2619,11 +2684,13 @@ fseg_free_extent(
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
) )
{ {
ut_ad(mtr != NULL);
buf_block_t* xdes; buf_block_t* xdes;
xdes_t* descr = xdes_get_descriptor(space, page, &xdes, mtr); xdes_t* descr = xdes_get_descriptor(space, page, mtr, &xdes);
if (!descr) {
ut_ad(space->is_stopping());
return;
}
ut_a(xdes_get_state(descr) == XDES_FSEG); ut_a(xdes_get_state(descr) == XDES_FSEG);
ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8)); ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
...@@ -2705,8 +2772,12 @@ fseg_free_step( ...@@ -2705,8 +2772,12 @@ fseg_free_step(
const uint32_t header_page = page_get_page_no(page_align(header)); const uint32_t header_page = page_get_page_no(page_align(header));
fil_space_t* space = mtr->x_lock_space(space_id); fil_space_t* space = mtr->x_lock_space(space_id);
buf_block_t* xdes; xdes_t* descr = xdes_get_descriptor(space, header_page, mtr);
xdes_t* descr = xdes_get_descriptor(space, header_page, &xdes, mtr);
if (!descr) {
ut_ad(space->is_stopping());
DBUG_RETURN(true);
}
/* Check that the header resides on a page which has not been /* Check that the header resides on a page which has not been
freed yet */ freed yet */
...@@ -2715,10 +2786,13 @@ fseg_free_step( ...@@ -2715,10 +2786,13 @@ fseg_free_step(
buf_block_t* iblock; buf_block_t* iblock;
const ulint zip_size = space->zip_size(); const ulint zip_size = space->zip_size();
inode = fseg_inode_try_get(header, space_id, zip_size, mtr, &iblock); inode = fseg_inode_try_get(header, space_id, zip_size, mtr, &iblock);
if (space->is_stopping()) {
DBUG_RETURN(true);
}
if (inode == NULL) { if (inode == NULL) {
ib::info() << "Double free of inode from " ib::warn() << "Double free of inode from "
<< page_id_t(space_id, header_page); << page_id_t(space_id, header_page);
DBUG_RETURN(true); DBUG_RETURN(true);
} }
...@@ -2727,6 +2801,10 @@ fseg_free_step( ...@@ -2727,6 +2801,10 @@ fseg_free_step(
} }
descr = fseg_get_first_extent(inode, space, mtr); descr = fseg_get_first_extent(inode, space, mtr);
if (space->is_stopping()) {
DBUG_RETURN(true);
}
if (descr != NULL) { if (descr != NULL) {
/* Free the extent held by the segment */ /* Free the extent held by the segment */
fseg_free_extent(inode, iblock, space, xdes_get_offset(descr), fseg_free_extent(inode, iblock, space, xdes_get_offset(descr),
...@@ -2779,8 +2857,6 @@ fseg_free_step_not_header( ...@@ -2779,8 +2857,6 @@ fseg_free_step_not_header(
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
) )
{ {
ulint n;
xdes_t* descr;
fseg_inode_t* inode; fseg_inode_t* inode;
const uint32_t space_id = page_get_space_id(page_align(header)); const uint32_t space_id = page_get_space_id(page_align(header));
...@@ -2789,15 +2865,24 @@ fseg_free_step_not_header( ...@@ -2789,15 +2865,24 @@ fseg_free_step_not_header(
fil_space_t* space = mtr->x_lock_space(space_id); fil_space_t* space = mtr->x_lock_space(space_id);
buf_block_t* iblock; buf_block_t* iblock;
inode = fseg_inode_get(header, space_id, space->zip_size(), mtr, inode = fseg_inode_try_get(header, space_id, space->zip_size(),
&iblock); mtr, &iblock);
if (space->is_stopping()) {
return true;
}
if (!inode) {
ib::warn() << "Double free of "
<< page_id_t(space_id,
page_get_page_no(page_align(header)));
return true;
}
if (!space->full_crc32()) { if (!space->full_crc32()) {
fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr); fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr);
} }
descr = fseg_get_first_extent(inode, space, mtr); if (xdes_t* descr = fseg_get_first_extent(inode, space, mtr)) {
if (descr != NULL) {
/* Free the extent held by the segment */ /* Free the extent held by the segment */
fseg_free_extent(inode, iblock, space, xdes_get_offset(descr), fseg_free_extent(inode, iblock, space, xdes_get_offset(descr),
mtr mtr
...@@ -2810,7 +2895,7 @@ fseg_free_step_not_header( ...@@ -2810,7 +2895,7 @@ fseg_free_step_not_header(
/* Free a frag page */ /* Free a frag page */
n = fseg_find_last_used_frag_page_slot(inode); ulint n = fseg_find_last_used_frag_page_slot(inode);
ut_a(n != ULINT_UNDEFINED); ut_a(n != ULINT_UNDEFINED);
...@@ -2856,15 +2941,15 @@ fseg_get_first_extent( ...@@ -2856,15 +2941,15 @@ fseg_get_first_extent(
} else if (flst_get_len(inode + FSEG_FREE) > 0) { } else if (flst_get_len(inode + FSEG_FREE) > 0) {
first = flst_get_first(inode + FSEG_FREE); first = flst_get_first(inode + FSEG_FREE);
} else { } else {
return(NULL); return nullptr;
} }
DBUG_ASSERT(first.page != FIL_NULL); if (first.page == FIL_NULL) {
ut_ad("corruption" == 0);
buf_block_t *xdes; return nullptr;
}
return(first.page == FIL_NULL ? NULL return xdes_lst_get_descriptor(*space, first, mtr);
: xdes_lst_get_descriptor(space, first, &xdes, mtr));
} }
#ifdef UNIV_BTR_PRINT #ifdef UNIV_BTR_PRINT
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2019, 2020, MariaDB Corporation. Copyright (c) 2019, 2021, MariaDB Corporation.
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
...@@ -150,10 +150,10 @@ static void flst_insert_after(buf_block_t *base, uint16_t boffset, ...@@ -150,10 +150,10 @@ static void flst_insert_after(buf_block_t *base, uint16_t boffset,
else else
{ {
buf_block_t *block; buf_block_t *block;
flst_node_t *next= fut_get_ptr(add->page.id().space(), add->zip_size(), if (flst_node_t *next= fut_get_ptr(add->page.id().space(), add->zip_size(),
next_addr, RW_SX_LATCH, mtr, &block); next_addr, RW_SX_LATCH, mtr, &block))
flst_write_addr(*block, next + FLST_PREV, flst_write_addr(*block, next + FLST_PREV,
add->page.id().page_no(), aoffset, mtr); add->page.id().page_no(), aoffset, mtr);
} }
flst_write_addr(*cur, cur->frame + coffset + FLST_NEXT, flst_write_addr(*cur, cur->frame + coffset + FLST_NEXT,
...@@ -201,10 +201,10 @@ static void flst_insert_before(buf_block_t *base, uint16_t boffset, ...@@ -201,10 +201,10 @@ static void flst_insert_before(buf_block_t *base, uint16_t boffset,
else else
{ {
buf_block_t *block; buf_block_t *block;
flst_node_t *prev= fut_get_ptr(add->page.id().space(), add->zip_size(), if (flst_node_t *prev= fut_get_ptr(add->page.id().space(), add->zip_size(),
prev_addr, RW_SX_LATCH, mtr, &block); prev_addr, RW_SX_LATCH, mtr, &block))
flst_write_addr(*block, prev + FLST_NEXT, flst_write_addr(*block, prev + FLST_NEXT,
add->page.id().page_no(), aoffset, mtr); add->page.id().page_no(), aoffset, mtr);
} }
flst_write_addr(*cur, cur->frame + coffset + FLST_PREV, flst_write_addr(*cur, cur->frame + coffset + FLST_PREV,
...@@ -254,9 +254,10 @@ void flst_add_last(buf_block_t *base, uint16_t boffset, ...@@ -254,9 +254,10 @@ void flst_add_last(buf_block_t *base, uint16_t boffset,
? add->frame + addr.boffset ? add->frame + addr.boffset
: fut_get_ptr(add->page.id().space(), add->zip_size(), addr, : fut_get_ptr(add->page.id().space(), add->zip_size(), addr,
RW_SX_LATCH, mtr, &cur); RW_SX_LATCH, mtr, &cur);
flst_insert_after(base, boffset, cur, if (c)
static_cast<uint16_t>(c - cur->frame), flst_insert_after(base, boffset, cur,
add, aoffset, mtr); static_cast<uint16_t>(c - cur->frame),
add, aoffset, mtr);
} }
} }
...@@ -287,9 +288,10 @@ void flst_add_first(buf_block_t *base, uint16_t boffset, ...@@ -287,9 +288,10 @@ void flst_add_first(buf_block_t *base, uint16_t boffset,
? add->frame + addr.boffset ? add->frame + addr.boffset
: fut_get_ptr(add->page.id().space(), add->zip_size(), addr, : fut_get_ptr(add->page.id().space(), add->zip_size(), addr,
RW_SX_LATCH, mtr, &cur); RW_SX_LATCH, mtr, &cur);
flst_insert_before(base, boffset, cur, if (c)
static_cast<uint16_t>(c - cur->frame), flst_insert_before(base, boffset, cur,
add, aoffset, mtr); static_cast<uint16_t>(c - cur->frame),
add, aoffset, mtr);
} }
} }
...@@ -318,12 +320,12 @@ void flst_remove(buf_block_t *base, uint16_t boffset, ...@@ -318,12 +320,12 @@ void flst_remove(buf_block_t *base, uint16_t boffset,
else else
{ {
buf_block_t *block= cur; buf_block_t *block= cur;
flst_node_t *prev= prev_addr.page == cur->page.id().page_no() if (flst_node_t *prev= prev_addr.page == cur->page.id().page_no()
? cur->frame + prev_addr.boffset ? cur->frame + prev_addr.boffset
: fut_get_ptr(cur->page.id().space(), cur->zip_size(), prev_addr, : fut_get_ptr(cur->page.id().space(), cur->zip_size(), prev_addr,
RW_SX_LATCH, mtr, &block); RW_SX_LATCH, mtr, &block))
flst_write_addr(*block, prev + FLST_NEXT, flst_write_addr(*block, prev + FLST_NEXT,
next_addr.page, next_addr.boffset, mtr); next_addr.page, next_addr.boffset, mtr);
} }
if (next_addr.page == FIL_NULL) if (next_addr.page == FIL_NULL)
...@@ -332,12 +334,12 @@ void flst_remove(buf_block_t *base, uint16_t boffset, ...@@ -332,12 +334,12 @@ void flst_remove(buf_block_t *base, uint16_t boffset,
else else
{ {
buf_block_t *block= cur; buf_block_t *block= cur;
flst_node_t *next= next_addr.page == cur->page.id().page_no() if (flst_node_t *next= next_addr.page == cur->page.id().page_no()
? cur->frame + next_addr.boffset ? cur->frame + next_addr.boffset
: fut_get_ptr(cur->page.id().space(), cur->zip_size(), next_addr, : fut_get_ptr(cur->page.id().space(), cur->zip_size(), next_addr,
RW_SX_LATCH, mtr, &block); RW_SX_LATCH, mtr, &block))
flst_write_addr(*block, next + FLST_PREV, flst_write_addr(*block, next + FLST_PREV,
prev_addr.page, prev_addr.boffset, mtr); prev_addr.page, prev_addr.boffset, mtr);
} }
byte *len= &base->frame[boffset + FLST_LEN]; byte *len= &base->frame[boffset + FLST_LEN];
...@@ -369,6 +371,7 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr) ...@@ -369,6 +371,7 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr)
const flst_node_t *node= fut_get_ptr(base->page.id().space(), const flst_node_t *node= fut_get_ptr(base->page.id().space(),
base->zip_size(), addr, base->zip_size(), addr,
RW_SX_LATCH, &mtr2); RW_SX_LATCH, &mtr2);
ut_ad(node);
addr= flst_get_next_addr(node); addr= flst_get_next_addr(node);
mtr2.commit(); mtr2.commit();
} }
...@@ -383,6 +386,7 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr) ...@@ -383,6 +386,7 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr)
const flst_node_t *node= fut_get_ptr(base->page.id().space(), const flst_node_t *node= fut_get_ptr(base->page.id().space(),
base->zip_size(), addr, base->zip_size(), addr,
RW_SX_LATCH, &mtr2); RW_SX_LATCH, &mtr2);
ut_ad(node);
addr= flst_get_prev_addr(node); addr= flst_get_prev_addr(node);
mtr2.commit(); mtr2.commit();
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2019, MariaDB Corporation. Copyright (c) 2019, 2021, MariaDB Corporation.
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
...@@ -39,7 +39,7 @@ Created 12/13/1995 Heikki Tuuri ...@@ -39,7 +39,7 @@ Created 12/13/1995 Heikki Tuuri
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return pointer to a byte in (*ptr_block)->frame; the *ptr_block is @return pointer to a byte in (*ptr_block)->frame; the *ptr_block is
bufferfixed and latched */ bufferfixed and latched */
UNIV_INLINE inline
byte* byte*
fut_get_ptr( fut_get_ptr(
ulint space, ulint space,
...@@ -57,10 +57,15 @@ fut_get_ptr( ...@@ -57,10 +57,15 @@ fut_get_ptr(
|| (rw_latch == RW_X_LATCH) || (rw_latch == RW_X_LATCH)
|| (rw_latch == RW_SX_LATCH)); || (rw_latch == RW_SX_LATCH));
block = buf_page_get(page_id_t(space, addr.page), zip_size, block = buf_page_get_gen(page_id_t(space, addr.page), zip_size,
rw_latch, mtr); rw_latch, nullptr, BUF_GET_POSSIBLY_FREED,
mtr);
ptr = buf_block_get_frame(block) + addr.boffset; if (!block) {
} else if (block->page.status == buf_page_t::FREED) {
block = nullptr;
} else {
ptr = buf_block_get_frame(block) + addr.boffset;
}
if (ptr_block != NULL) { if (ptr_block != NULL) {
*ptr_block = block; *ptr_block = block;
......
...@@ -633,11 +633,17 @@ struct mtr_t { ...@@ -633,11 +633,17 @@ struct mtr_t {
{ ut_ad(!m_commit || m_start); return m_start && !m_commit; } { ut_ad(!m_commit || m_start); return m_start && !m_commit; }
/** @return whether the mini-transaction has been committed */ /** @return whether the mini-transaction has been committed */
bool has_committed() const { ut_ad(!m_commit || m_start); return m_commit; } bool has_committed() const { ut_ad(!m_commit || m_start); return m_commit; }
/** @return whether the mini-transaction is freeing an index tree */
bool is_freeing_tree() const { return m_freeing_tree; }
/** Notify that the mini-transaction is freeing an index tree */
void freeing_tree() { m_freeing_tree= true; }
private: private:
/** whether start() has been called */ /** whether start() has been called */
bool m_start= false; bool m_start= false;
/** whether commit() has been called */ /** whether commit() has been called */
bool m_commit= false; bool m_commit= false;
/** whether freeing_tree() has been called */
bool m_freeing_tree= false;
#endif #endif
/** The page of the most recent m_log record written, or NULL */ /** The page of the most recent m_log record written, or NULL */
......
...@@ -362,6 +362,7 @@ void mtr_t::start() ...@@ -362,6 +362,7 @@ void mtr_t::start()
ut_d(m_start= true); ut_d(m_start= true);
ut_d(m_commit= false); ut_d(m_commit= false);
ut_d(m_freeing_tree= false);
m_last= nullptr; m_last= nullptr;
m_last_offset= 0; m_last_offset= 0;
......
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