mirror of
https://github.com/MariaDB/server.git
synced 2026-04-20 15:25:33 +02:00
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.
This commit is contained in:
parent
a81aec1505
commit
f619d79bda
7 changed files with 318 additions and 220 deletions
|
|
@ -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)
|
||||||
@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(
|
||||||
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)
|
||||||
@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(
|
||||||
/* 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(
|
||||||
@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,
|
||||||
@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(
|
||||||
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.
|
||||||
@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(
|
||||||
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(
|
||||||
|
|
||||||
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(
|
||||||
{
|
{
|
||||||
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(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
|
||||||
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(
|
||||||
|
|
||||||
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(
|
||||||
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(
|
||||||
|
|
||||||
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)
|
||||||
/* 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)
|
||||||
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(
|
||||||
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(
|
||||||
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(
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
|
||||||
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(
|
||||||
|
|
||||||
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(
|
||||||
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 @@ take_hinted_page:
|
||||||
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 @@ got_hinted_page:
|
||||||
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(
|
||||||
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(
|
||||||
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(
|
||||||
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(
|
||||||
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(
|
||||||
@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_LOG("fseg_free_page", "space_id: " << space->id
|
DBUG_PRINT("fseg_free_page",
|
||||||
<< ", page_no: " << offset);
|
("space_id: " ULINTPF ", page_no: %u", space->id, offset));
|
||||||
|
|
||||||
seg_inode = fseg_inode_get(seg_header, space->id, space->zip_size(),
|
if (fseg_inode_t *seg_inode= fseg_inode_try_get(seg_header,
|
||||||
mtr,
|
space->id, space->zip_size(),
|
||||||
&iblock);
|
mtr, &iblock))
|
||||||
if (!space->full_crc32()) {
|
{
|
||||||
fil_block_check_type(*iblock, FIL_PAGE_INODE, mtr);
|
if (!space->full_crc32())
|
||||||
}
|
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(
|
||||||
#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(
|
||||||
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(
|
||||||
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(
|
||||||
}
|
}
|
||||||
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(
|
||||||
#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(
|
||||||
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(
|
||||||
|
|
||||||
/* 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(
|
||||||
} 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);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
buf_block_t *xdes;
|
return xdes_lst_get_descriptor(*space, first, mtr);
|
||||||
|
|
||||||
return(first.page == FIL_NULL ? NULL
|
|
||||||
: xdes_lst_get_descriptor(space, first, &xdes, mtr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIV_BTR_PRINT
|
#ifdef UNIV_BTR_PRINT
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
? 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,
|
||||||
? 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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
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
|
||||||
@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(
|
||||||
|| (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 @@ public:
|
||||||
{ 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()
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue